2014年6月21日星期六

又一個 benchmark

從別人的網誌看到一篇做 benchmarking 的論文:A Comparison of Programming Languages in Economics,其中有些令人驚奇的結果。

比較不同程式語言的執行效率,往往引起極大爭議。一來,作比較時,實際上比較的不單單是語言本身,還牽涉了 compiler 或者 interpreter,以及程式庫。二來,各種語言均有其獨特的 features。如何用不同語言來實作同一個算則才算公平,並無定論。幾年前 Google 有人寫了篇 Loop Recognition in C++/Java/Go/Scala,對所涉各種語言,都找來熟悉該語言的工程師,先用最自然的寫法來實作同一個算則,然後再優化程式。照道理這樣做已經很公道,可是還是有工程師事後表示,若早知程式是用來做 benchmarking 的話,寫法就會不同云云。可見無論是再公平的程序,亦說服不了所有人。

三來,許多時於網上見到的都是 micro-benchmarks,它們實作的,往往都是生安白造兼且過份簡單的算則,而非來自現實問題、難度適中的算則。今次這篇論文,和前述 Google 工程師所用的算則,皆有現實背景,既不太難,亦不太易,很適合 benchmarking 用。

我自己寫的程式通常都是做科學計算,用得較多的語言中,我最熟悉的是 Matlab 和 C++,其次是 Python 和 Java,再而是 R。印象中,若計算以矩陣為主(我指的是「矩陣」matrix,不是「陣列」array),則前四種語言的表現皆差不多一樣,原因是除了 C++(但 C++ 也可以)外,Matlab, Python 或 Java 基本上都只是呼叫 BLAS 程式庫。若程式的瓶頸並非矩陣計算,則各種語言分別很大。通常若執行一個 C++ 程式要花一個時間單位,那麼 Java 就要大約 2-3 倍時間,Matlab 不用 Mex 則 6-10倍,而 Python 則時快時慢,但粗略地說,和 Matlab 同級。R 則慢過蝸牛,若講求速度的話,完全不用考慮。

那今次這篇 benchmarking 論文的結果又如何?答案是仍是 C++ 最快。各實作程式所花的時間(以 C++ 為 1.0)如下:

C++ (1.00) < Fortran (1.07) < Matlab, Mex (1.29) < Python/Numba (1.57) < Java (2.10) < Julia (2.70) < Mathematica (3.83) < Pypy (45.16) < CPython (155.31)。

以 C++, Matlab 和 R 來說,結果和我的經驗相符。然而,Julia 和 Python 的表現卻令我意外。如本網誌舊文所說,Julia 這種語法和 Matlab 有點相似的新語言可視為 "a general purpose programming language with a bias towards scientific computing"。其設計者曾於公式網站上,吹噓 Julia 有接近 C++ 的速度,然而網站上的 benchmarks,都不是來自現實問題。因此,今次 Julia 的超卓表現,應有助其宣傳攻勢。

Python 則既慢得意外,也快得意外。PyPy 和 CPython 皆比 C++ 慢了接近兩個數量級,實在始料不及。與此同時,一個我以前未聽過的 Python package,叫 Numba,卻做出 1.57 這個難以置信的結果。若其他範疇的 Python/Numba 程式皆有此表現,何止 Julia 活不了,相信連 Java 及 C++ 皆可殺掉。

不過話說回來,這個 benchmark 未必公正。從它的源程式所見,瓶頸位似乎是二維陣列的 array access。然而用各語言實作時,作者似乎一律假設二維陣列為 column-major 的。這樣就對 Fortran, Matlab 和 Julia 有利,卻不利使用 row-major convention 的 C++ 與 Python 了。無論如何,benchmark 只能作參考,不能一概而論,但今次 Julia 和 Python/Numba 的表現均相當優秀,值得關注。

沒有留言: