負責Unity繪圖引擎架構與發展的元老工程師Aras Pranckevičius,在個人部落格發表不看好C++ 20新功能Ranges的文章,而其在推特上的貼文也引來許多遊戲開發工程師表達相同的感受。他提到,C++的編譯時間與偵錯建置(Debug Build)效能非常重要,但是C++ 20的新功能Ranges卻讓這兩者都大幅增加。

11月ISO C++委員會在聖地亞哥召開了有史以來最大規模的會議,就C++ 20的語言更新草案進行討論,而決議之一便是決定加入Ranges概念。Ranges是即將在C++ 20加入的新語法功能,Ranges用來幫助操作範圍概念,能夠讓開發者簡單的迭代具有開始和結束範圍,並回傳行為類似迭代器的物件。Ranges能夠讓語法更為簡潔,使程式碼閱讀者不再需要自己解析複雜的for迴圈邏輯。

而主推Ranges和Concepts進入標準函式庫的Eric Nieble,在自己的部落格發表標題為Standard Ranges的文章,然而卻在Aras Pranckevičius發表評論之後,引來了部分遊戲開發者的討論,多數表達了反對意見。

 

Aras Pranckevičius使用目前最佳近似實作,由Eric Nieble撰寫的range-v3,與簡單版C++進行比較,他指出,C++ 20可能的問題至少有兩個,編譯時間與執行效能。他以Eric Nieble在自己部落格解釋Ranges功能的畢氏三元數為例,以使用Ranges的C++編譯程式碼,編譯時間長達2.92秒,比簡單版C++的0.064秒還要多2.85秒,他表示,現代的CPU可以在3秒的時間,進行很大量的操作,像是以Clang在偵錯模式中編譯完整資料庫引擎SQLite只要0.9秒,他質疑,編譯畢氏三元數的5行程式碼,卻需要編譯整個資料庫引擎的3倍時間。

Aras Pranckevičius指出,編譯時間是編譯大型C++程式碼庫痛苦的來源,他隨意列舉Chromium、Clang/LLVM或UE4專案,都能讓開發者輕易的體驗這件事,他指出,編譯時間就是一個C++待解決的大問題,而且應該在列表中排名之一,但是整個C++社群卻假裝這不是個問題。

由於在每個C++版本都會有更多的內容被放進標頭檔中,而且不像是C只在標頭檔案放入結構聲明或是函式原型,C++會把整個模板化的類別和函式都加入。range-v3是一個大小1.8MB的程式標頭檔,而且即便預編譯標頭檔,也只省下了0.7秒,整個編譯時間仍然長達2.24秒,比簡單版C++仍然長2.1秒。

另外,Aras Pranckevičius也提到,非最佳化建置效能也是非常重要的,在畢氏三元數的例子中,擁有Ranges的C++執行時間為300毫秒,而簡單版的C++卻只要2毫秒,也就是說執行效能慢了150倍,他認為,執行時間多2到3倍可以接受,慢10倍以上可能代表無法使用,而有Ranges的C++卻是百倍以上。

執行效能對於遊戲程式來說非常重要,Aras Pranckevičius表示,或許在部分應用偵錯模式中慢10或100倍的時間,只是比較擾人,但是在遊戲中,當每秒只有2個影格,則已經不是感覺上的問題,而是從根本上無法達到玩遊戲的體驗。即便建置最佳化後的執行效能與簡單版本相同,但Aras Pranckevičius提到,要對最佳化的程式碼偵錯非常困難,這增加了工作難度。

相較之下,以C#實作畢氏三元數,使用Mono編譯器編譯需要0.2秒,而簡單版的C#則是0.17秒,兩者相去不遠。Aras Pranckevičius認為,雖然C++ 20被稱為現代C++,但事實上這些變化,並沒有因為是「現代」而變得更好,大多數遊戲開發人員都還停留在C++ 11、14或是17的版本,無論C++ 20增加了什麼新功能,編譯時間與偵錯建置效能太差就毫無用武之地。

儘管Aras Pranckevičius的批評引起不少遊戲開發者的聲援贊同,但range設計目的是為了簡化複雜的C++程式碼,超多行數的大型程式碼是否會如簡單幾行的畢氏三元數程式一樣,遭遇到同樣嚴重的效能問題,Aras Pranckevičius則沒有進一步舉例實測。


Advertisement

更多 iThome相關內容