Julia

なんだか寝付けないので,最近の状況を踏まえてJuliaのことをQA形式で書こうと思います。Julia高速チュートリアルのアクセス数をみると,2018年早々プチブームになってるのがわかりますね。
image.png

なんでJuliaを使うのか

Juliaは比較的新しい言語で,もともと数値計算のために開発が開始されました。今までこの目的で使われていたのは,コンパイル言語だとFortranやC++,スクリプト言語だとMATLAB/OctaveやPython(特にNumPyやSciPy)でしょう。Juliaが特に優れている点としては,

  • 簡潔で平易な文法
  • 動的な実行が可能
  • 線形代数で使う関数が標準で用意されている(OpenBLASやLAPACKなど)
  • Just-in-time (JIT)コンパイルを行うため処理が高速

というのが挙げられます。つまるところ,次の図で示されるように,Juliaは少ないコード量で最大限のパフォーマンスを出せるように設計された言語ということです。
image.png
The Julia Language is the Way of the Future

誰が開発しているのか

Juliaの開発はコミュニティベースです。誰でも開発に参加できます。JuliaLang/juliaがレポジトリです。現在の主要な開発者は,その多くがJulia Computing, Inc.という会社に所属していますが,プルリクエストを送ったり開発の議論に参加したりは自由です。Juliaの始まりについてはJulia: A Fresh Approach to Numerical Computingという論文を参照下さい。

どのJuliaを使えば良いのか

2018年1月6日現在では,v0.6.2が最新版です。Windows・macOS・Linuxの最新版はバイナリで公式サイトから入手できます。これをダウンロードして使うのが一番ラクで確実です。どうしても自分でビルドしたい場合は,Juliaのレポジトリをクローンして,お好きなリビジョンをチェックアウト後にmakeを実行するとビルドできます(恐らく数時間はかかります)。

1.0はいつ出るのか

もうすぐだと思います。恐らく2-3ヶ月のうちには出るのではないかと思います。開発版では1.0に含まれるであろう機能の実装はほとんど出揃っていて,その品質を上げている段階のようです。1.0が出れば,恐らく数年は安定して使えると思います。

Fortran/C++より遅いのか

コンパイラや環境によりけりなので,なんとも言えないです。ほとんど場合は,ちゃんと書けば同程度のパフォーマンスが出ると思ってもらって問題ないと思います。パフォーマンスが大きく劣るとしたら,以下のようなケースが考えられます。

  • Juliaに優しい「ちゃんとした」コードじゃない (後述)
  • セマンティックが違う (例: 整数と浮動小数点数のべき乗の違い)
  • Juliaではまだサポートが弱いSIMDやmultithreadingを使った並列計算

JuliaはMATLAB/Pythonより速いのか

たいてい速いです。特に,ループや関数呼び出しのコストは,ちゃんと書けばコンパイル言語のそれと比べて遜色ないので,パフォーマンスのためにFortranやC++を書くことはほとんどないです。たまに,行列積などの計算でパフォーマンスの比較をしようとしているコードを見かけますが,どの言語を使っても裏で使われるのはBLASになるので,BLASの実装依存になりあまり意味がない比較です。

「ちゃんと書けば」とはどういうことか

Juliaは実行時に型推論をしてコンパイルをします。型推論の結果,変数の型が上手く推論できないと動的な実行にフォールバックします。このような動的な実行では呼び出すメソッドの探索などに時間がかかるため,遅くなります。しかし,大抵の場合は型が決定できるようにプログラムを書くことができるため,型が決定できるように「ちゃんと」書くとJuliaは速いコードを生成します。

どうすると型が決定できないのか

例えば,x = rand() > 0.5 ? 42 : 3.14というコードがあったとしましょう。変数xの型は1/2の確率で整数型になり,1/2の確率で浮動小数点数型になります。これはrand関数を呼び出して帰ってくる値を見るまで分かりませんので,xの型は決定できません。すると,速いコードが生成できなくなります。また,定数でない大域変数があった場合,この大域変数の型はいつでもどこからでも変更できてしまいますので,その大域変数を参照している部分のコードでは型が決定できないことがあります。このように型が決定できない状況をJulia界隈ではtype-instability(型不安定)と呼び,パフォーマンス上の問題となりうるコードと認識されています。しかし,次期バージョンのJulia 1.0では,この影響は限定的になるようです。

コンパイルはいつ起きるのか

Juliaのコンパイル単位は関数です。関数が呼び出されると,引数の型が決定しますので,それで型推論を行いコンパイルをします。それ以降,同じ関数を同じ型の引数で呼び出すと,前もってコンパイルされたコードが呼び出されます。なので,初回の関数呼び出しではコンパイルのコストが余分にかかり,若干実行が遅れます。将来的にはコンパイルする価値のない関数はコンパイルしないなどのヒューリスティックが入る可能性がありますが,現在(v0.6)は最初の関数呼び出しの際にコンパイルするようになっています。

パッケージの読み込みが遅いのはどうすればいいのか

今のところ,取れる手段はあまりないです。パッケージは初回の読み込み時に中間状態をキャッシュするようになっているため,初回の読み込みは特に時間がかかります。また,PackageCompiler.jlという予め関数などをコンパイルしてキャッシュする仕組みもありますが,つい最近リリースされたばかりなので,どれくらい現実的に使えるかは検証していないです。読み込みが遅いのは,今までJuliaの開発が主に機能の拡充と実行のスループットを上げる方向に注力してきたからです。今後実用的にJuliaが使われるようになっていくと,コンパイル時間の削減も重要な要素となってくると思うので,改善していくでしょう。

技術的な質問はどこですればいいのか

Juliaのユーザが集まるフォーラムはDiscouseです。ここは詳しい人が多く,頻繁に質問に目を通しているようなので,ここで質問するのが一番です。Juliaコミュニティにはやたら数値計算に詳しい人や文字列に詳しい人など色々いますので,そういう質問もある程度対応できると思います。