Julia焦慮?這有份Facebook軟體工程師的測試差評

大資料文摘發表於2018-08-10

近日,MIT CSAIL 實驗室正式釋出了 Julia 1.0,不少人稱,該語言結合了C語言的效能和Python 的易上手性,被稱為最聰明的一群大腦創造出的現代程式語言。

Julia 官網:

https://julialang.org/

Julia Github地址:

https://github.com/JuliaLang

自誕生之日起,Julia語言就備受關注。但是,這門“未來的語言”真的值得所有人學習嗎?

在Julia初誕生之初,一位來自Facebook的軟體工程師Victor Zverovich對這門語言做了一個效能測評,他從效能、語言、安全性、Library、發展上詳細敘述了Julia的特質,最終得出了“give up on Julia”的結論。

儘管這份“買家秀”距離今天時間略久,Julia經過一年多的演進,在本週釋出時已有了很大的進步,但是一門語言自誕生之日,其基因畢竟已經攜帶了某種特性,因此這篇文章現在讀起來仍然有一些不錯的參考價值。

Julia焦慮?這有份Facebook軟體工程師的測試差評

作者Victor Zverovich個人主頁:

http://www.zverovich.net/

當然,作為一門正在被追捧的語言,Julia還是值得了解。以下兩個視訊可以幫你迅速瞭解並安裝嘗試一下這門語言。

第一個視訊向python使用者詳細介紹了Julia的效能、特徵。演講來自IBM論壇,演講者有1.5年Julia使用經驗,也是杜克大學技術神經網路實驗室研究員,感興趣的同學可以戳視訊觀看


在官方釋出後,也有人制作了一個詳細的Julia安裝使用手把手教學視訊


最後,Victor Zverovich的這份Julia差評買家秀,可能可以部分緩解你的程式語言焦慮。

文章連結:

http://www.zverovich.net/2016/05/13/giving-up-on-julia.html

Julia焦慮?這有份Facebook軟體工程師的測試差評

首次瞭解Julia程式語言時,我對它非常熱衷。Julia語言的吸引力從官網上的功能列表就可見一斑:

  • 多分派:提供跨多種引數型別來組合定義函式的能力

  • 動態型別系統:文件,優化和分派的型別

  • 良好的效能,甚至能接近包括C語言在內的靜態編譯語言

  • 內建程式包管理器

  • 類似Lisp的巨集和其他超程式設計工具

  • 可以通過使用PyCall包來呼叫Python函式

  • 不需要包裝器或特殊API就能直接呼叫C函式:

  • 強大的類似shell的功能,用於管理其他程式

  • 專為並行和分散式計算而設計

  • 協同程式:輕量級“綠色”執行緒

  • 使用者自定義的型別與內建函式一樣快速、緊湊

  • 為不同的引數型別自動生成高效的專用程式碼

  • 針對數字和其他型別的優雅且可擴充套件的轉換

  • 對Unicode的有效支援,包括但不限於UTF-8

  • MIT 開源許可(MIT license):免費+開源

然而,隨著我對Julia語言的瞭解變得深入,親自上手實驗,我對它越來越不滿意了。我將在這篇文章中解釋為什麼。

效能

Julia焦慮?這有份Facebook軟體工程師的測試差評

當我看到Julia網站上報導的微基準測試時,我感受到了第一個次失望。粗淺瀏覽就能感受到其中的大問題

連結:

https://github.com/JuliaLang/julia/issues/4662

Julia比C或C++慢得多,這一點倒是沒有什麼可指責的,畢竟大多數語言都是。最令人失望的是其聲稱的表現與觀察到的表現之間的顯著差異。

例如,Julia中的一個簡單的hello world程式執行速度比Python的版本慢約27x,比C語言慢約187x。這些效能是Linux上執行的結果,雖然我自己不使用Windows,但別人告訴我在那個環境下的差異更明顯。

# test.jl println("Hello, World!")

# test.py print("Hello, World!")

#include <stdio.h> int main() {  printf("Hello, World!\n"); }

$ time julia test.jl Hello, World! real  0m0.371s user  0m0.240s sys  0m0.312s $ time python test.py Hello, World! real  0m0.014s user  0m0.004s sys  0m0.004s $ gcc -O3 test.c $ time ./a.out Hello, World! real  0m0.002s user  0m0.000s sys  0m0.000s

如果忽略啟動時間,Julia在簡單的陣列運算、矩陣運算以及迴圈上效能尚佳,但我們已經知道怎麼用Python或者其他語言來高效執行這些操作了。?

https://www.ibm.com/developerworks/community/blogs/jfp/entry/Python_Meets_Julia_Micro_Performance

不僅僅是指令碼,Julia的REPL的響應性優化需要很長時間才能啟動,並且在使用JIT編譯器(Just-in-Time Complier)時有明顯滯後。更讓人擔憂的是,這一問題的解決上似乎沒有太大進展。一年前使用時,REPL就是個大痛點,現在仍然如此。

除此之外,Julia程式的記憶體消耗過多。Julia上面hello world示例使用的記憶體比Python高18倍,比C高92倍。

可能的原因是Julia使用LLVM進行JIT編譯。LLVM非常適合作為靜態編譯語言的編譯器後端,但眾所周知,它在動態語言環境中無法達到同樣的效果。Unladen Swallow和最近從WebVM遷移的WebKit 就是值得注意的例子。?

https://en.wikipedia.org/wiki/Unladen_Swallow

https://webkit.org/blog/5852/introducing-the-b3-jit-compiler/

語言

在語言設計中,Julia也保留了一些現代程式語言很好的功能,但其語法仍是一大詬病。頗為模糊的語法大概只有MATLAB的忠粉會習慣。

當然,在可讀性方面,Julia也很難與Python競爭。人們常說,程式碼被讀比被寫的次數多。從這一點來看,Julia肯定有改進的餘地。表示式語法更合理了,但仍然有一些非正統的選擇操作符,標點符號和多行註釋的語法(例如#= \ // $?),這些註釋會給使用者帶來不少麻煩。

從1開始索引的設計決策也有待商榷。雖然在某些情況下它可能很方便,但在與所有使用基於0索引的主流程式語言進行互操作時,會增加錯誤的出現,也會增加額外工作。例如:

ret = @grb_ccall(delconstrs, Cint, (                 Ptr{Void},                 Cint,                 Ptr{Cint}),                  model, convert(Cint,numdel), idx.-1)

當然,有人可能會認為Julia並不是一種通用程式語言,而是一種數值計算語言。但是,正如現在的Python所展現的能力,程式語言並不必為了一個效能而在另一個效能上有所欠缺。

我想在本節中提到的最後一個問題是API文件。甚至與Doxygen相比,Julia標準文件系統都算得上退步,更不用說Sphinx了。它不依賴於語義標記,而採用基於Markdown的基本格式,更側重於展示。除了明顯的Markdown限制之外,這種格式也讓編寫異構專案的開發文件更麻煩了。

安全

當然,JNA-和ctypes型別的FFI確實很方便。然而,將其設定為與本機API介面的預設方式就會出現重大安全問題。C和C++都採用標頭檔案是有其原因的。手動宣告所有內容不僅耗時,而且容易出錯。在C Call 上出一點點問題都可能造成段錯誤(segmentation fault)。有意思的是,當因為官方示例有問題,我把文件中的程式碼從libc更改為libc.so.6,就出現了段錯誤。

julia> val = ccall((:getenv, "libc.so.6"), Ptr{UInt8}, (Ptr{UInt8},), var) signal (11): Segmentation fault

這個效能上,Python甚至Java與C的API都更好用。

Libraries

Julia目前缺乏的另一個重要內容是庫(Library),尤其是標準庫。

例如,文字格式(.txt)是人們可能想到的最基本和最常用的語言形式之一,而Julia甚至落後於C++ 98。標準庫提供了@printf和@sprintf,但這些都是無法擴充套件的。你甚至無法將它們對複數進行格式化。Julia確實有一個基本字串插值,但目前來看,它似乎只對最基本的格式有用。

作為巨集,@printf/ @sprintf為每個格式字串生成自定義程式碼,希望它比在執行時解析它更有效。有人甚至說,Julia語言“要趕上C語言還需要一段時間,更不用說擊敗它了”?。

http://stackoverflow.com/q/19783030/471164

舉個例子,讓我們看一下C中的一個簡單的printf示例:

void f(char *buffer, const char *a, double b) {  sprintf(buffer, "this is a %s %g", a, b); }

它只彙編了幾條指令:

f: .LFB23: .cfi_startproc movq  %rsi, %r8 movl  $.LC0, %ecx movq  $-1, %rdx movl  $1, %esi movl  $1, %eax jmp  __sprintf_chk .cfi_endproc

下面是julia版本:

function f(a, b)  @sprintf("this is a %s %g", a, b) end

執行code_native(f, (ASCIIString, Float64))並檢視輸出,您將看到將近500條指令。可以想象一下@(s)printf呼叫的次數。這個數量是相當巨大的。由於經常使用文字格式,這種指令方式可能會產生嚴重的程式碼冗長問題。C語言版本可能沒有這麼安全,但有一些安全的替代方案,也並不會犧牲程式碼的緊湊性。

用於單元測試的庫也非常基礎,至少與C++和Java中的庫相比是這樣。

發展

我對大型程式碼庫並不陌生,但在考慮是否為Julia專案做開源貢獻時,我發現程式碼庫簡直就是C,C++,Julia和Lisp的混搭,不得不望而卻步,儘管我對LLVM在後端的使用有一些經驗。原因並不是因為不喜歡混搭中的某一種語言,而是該專案要求開發人員同時精通數種程式語言。這相當於只有擁有獨特專業知識或在特定領域內工作的開發者才有能力參與到專案中。正如Dan Luu所說:

Julia開發組是一個由才華橫溢的人員構成的小團隊。他們基本上可以將所有程式碼儲存在各自大腦中,也可以取得很大的進步,然而代價是其他開發者更難以做出貢獻。這值得嗎?很難說。

我不確定這種方法是否可取,其他人報告Julia開發速度放緩 :

Julia的發展的確越來越慢。在過去的9個月裡,我都沒怎麼見過它。

總結

總而言之,目前的Julia語言有如下問題尚待改進:

  • 效能問題,包括啟動時間長和JIT編譯的延遲

  • 與其他語言的互操作性問題,

  • 文字格式化工具不足,

  • 缺乏良好的單元測試框架,

  • 預設情況下不安全的本地API介面,

  • 不必要的複雜程式碼庫,

  • 對bug修復的不夠重視

儘管如此,我認為該語言可以作為matlab的開源替代品,因為這門程式語言的語法可能對matlab使用者很有吸引力,甚至會撼動Python在數值計算的地位。

相關文章