Go 1.18加入了眾所期待的泛型(Generics)功能,社群普遍認為這將使程式碼更乾淨,且更容易重用。而推特、YouTube和Slack等服務都在使用的無伺服器資料庫平臺Planetscale,該公司工程師經過測試,發現泛型可能會讓許多Go程式碼執行速度變慢,而這與Go選擇實作泛型的方法有關。

Planetscale工程師提到,程式語言實作泛型的常見方法有兩種,分別是裝箱(Boxing)和單態化(Monomorphization),而單態化也是C++、D和Rust等系統語言實作泛型的設計選擇,這是因為這些語言想要以更長的編譯時間,來換取最終程式碼的效能提升。

編譯器在執行最佳化之前,開發者能以最終類型替換泛型中的類型占位符號,其所獲得的最佳化效果,是使用裝箱類型(Boxed Type)所無法相比的,至少開發者去虛擬化函式呼叫,也能夠擺脫虛擬表格,在最佳的情境中,開發者可以使用內嵌程式碼(Inline Code),而這又能夠進一步執行最佳化工作。

也就是說,單態化可以使泛型程式碼更快,但Planetscale指出,Go的泛型並非完全使用單態化,而是使用一種稱為GCShape Stenciling with Dictionaries的部分單態化技術,雖然這種方法大幅減少生成專有程式碼的數量,但是廣泛的單態化,卻不適合去虛擬化、內嵌或是任何類型的效能最佳化,Planetscale認為,對絕大多數的Go程式碼來說,使用泛型意味著讓程式碼執行速度變慢。

由於PlanetScale使用開源資料庫叢集系統Vitess,而Vitess為一個大型且複雜的Go應用程式,因此成為測試新Go語言的絕佳平臺。經過測試,PlanetScale工程師歸納出在Go中使用泛型的幾點訣竅,包括盡量在資料結構中使用泛型,如此不只使資料結構更易於使用且效能更好,同時這也是目前最佳的泛型使用情境。

開發者最好也不要使用泛型去虛擬化或是內嵌方法呼叫,在任何情況下都不要將介面傳遞給泛型函式,另外,開發者也不應該重寫以介面為基礎的API來使用泛型,這些做法都會使程式碼變慢。

對於使用泛型可能讓Go程式碼變慢的情況,PlanetScale工程師失望地表示,在編譯語言中使用執行時字典,並非正確的技術選擇。工程師們將這個問題指向Go 1.18中,完全單態化提案裡的風險章節,其提到使用字典實現的原因,是因為單態化程式碼很慢,但工程師認為,這是誤導性假設。

以Go泛型目前的狀態,限制了在效能敏感的程式碼中的應用,PlanetScale工程師認為,Go官方應該重新評估使用執行時字典來縮短編譯時間的選擇,並在未來的Go版本,能實現更完全的單態化。

熱門新聞

Advertisement