雛形書庫

An Unmoving Arch-Archive

Dynamism and Performance in Julia

動的型付けと高性能を両立するJuliaの言語設計を学びます。

Original Paper

免責事項

内容の正確性には可能な限り留意しておりますが、必ずしも正確性を保証するものではありません。 内容に基づく一切の結果について、一切の責任を負いかねます。 予めご了承ください。

はじめに:この論文について

国際会議OOPSLAで発表された、年若いプログラミング言語Juliaの言語設計についての論文。 論文のタイトルにある "reconcile" とは「和解」とか「調和」を意味していて、一般的には両立しないと考えられている動的型付けであること(すなわち生産的であること)と高速な実行性能を、巧みな言語設計により両立させました、という内容。 筆頭著者のJeff Bezanson氏の所属は、彼が共同設立者の一人である会社Julia Computingということで、Juliaの中の人みずからがその言語設計を解説している。 ACMウェブサイトの論文ページでは、論文の他に講演の録画も見ることができて理解の助けになる。 リファレンスが英語だけだと少し辛かったことから、優れた和書である『1から始める Juliaプログラミング』を参照しながら読むことで、特に最適化周りの手法についての理解がかなり捗った。

1から始める Juliaプログラミング

1から始める Juliaプログラミング

プログラミング言語について

科学技術計算に使われるプログラミング言語には大きく分けて2種類ある; ひとつは開発がたやすく・生産性を重視した高水準の言語 (Python, MATLAB, R) であり、もう一つは実行性能に力点をおいた低水準の言語 (C, C++, Fortran) である。 何かアプリを作ろうとしたときには、まずは前者で作り始めることがままある。 そして解くべき問題が大きくなったり、複雑になってきたタイミングで、性能重視の言語へと書き直す。 しかしこのソフトウェアの移行作業は、しばしば大変な作業になる。

科学者たちはプログラミング言語における生産性と性能を橋渡しすることに長年取り組んできて、その例のひとつにROOTというデータ解析フレームワークがある。 ROOTは公式サイトによれば "An open-source data analysis framework used by high energy physics and others." を謳っていて、C++を拡張することで生産性と性能を両立した。 しかし論文でのROOTの説明はあっさりしていて、以下の一文でさらっと言及を終えている:

Most scientific fields, however, do not have the resources to build and maintain their own computational infrastructure.

ここを読む限りではROOTはあまり普及しなかったのだろうか、この論文を読んだだけだとよくわからなかった。

ここで、両者の橋渡しをする言語として新たに登場してきたのが今回のテーマであるJuliaである。

Juliaの特徴について

プログラミングの生産性を維持しつつ高速性能も実現する、Juliaのキーとなる特徴は以下の3つである:

  • Language design(言語設計)
  • Language implementation(言語の実行)
  • Programming style(プログラミングのスタイル)

このうち上の2つは言語の側の特徴だけど、それらに加わる3番目として、ユーザーがJuliaのプログラミングスタイルに習熟することも求められている。 『1から始める Juliaプログラミング』の第4章で書かれているように、Juliaの高速性能を十分に発揮するためには、ユーザー側がコンパイラにとって最適化しやすいコードを書くことが重要である。

論文第2章は、Fig. 3の機械語が読めないのでスキップ。 しかしACMウェブサイトの論文ページにある動画では、この第2章に対応する講演動画が掲載されていて、いかにして高速な実行を実現するかが説明されている(動画2:57あたり)。

Juliaの生産性と性能

生産性の観点より、Juliaでの実装にかかるコストを他の言語と比較したグラフがFig. 6になる。 ここではPyPy, V8, HotSpotとの比較になっていて、グラフの横軸は人年になっている。 一人の開発者が週2回コミットした場合を1人週として、コミット履歴からラフに見積もったもの。 Fig. 6のグラフによれば、Juliaは25人年以下と小さい値を保っているのに対し、PyPyとV8は100人年以上、HotSpotに至っては200人年に迫る大きな値を示している。 (ちなみに当然ながら、これはたった一人の開発者が100~200年をかけて開発したわけではない1)。

Juliaの生産性が高いことは(ラフな見積もりではあるが)わかったけれども、高速性能についてはどうだろうか。 論文ではC, Julia, JavaScript, Pythonの4つのプログラミング言語で、10個のベンチマークケースを走らせてその性能を確認している。 その結果がFig. 7にまとめられていて、4つの言語のなかではCがもっとも速いのだけれど、JuliaはCに次いで高速な性能を示している(ほぼすべてのケースで、Cの実行時間の2倍以内に収まる。とくにregexについてはCよりも高速)。次に速いのはJavaScriptで、Pythonは(Fig. 7のグラフを見る限りでは)残念ながらかなり遅い。

ベンチマークプログラムのような小さいケースでは、実世界の問題の参考にならないかもしれないが、規模のもっと大きなベンチマークのケースはまだ存在しない2。 しかしこれまでに発表されたいくつかの比較事例は、小さいベンチマークプログラムで示されている優れた高速性能が、より大きなプログラムでもそのまま当てはまるかもしれないことを示唆している。

Juliaの特徴について:詳細

第4章から第6章にかけて、前述のJuliaの3つの特徴

  • Language design(言語設計)
  • Language implementation(言語の実行)
  • Programming style(プログラミングのスタイル)

がひとつずつ詳説されている。 ここで、Juliaがもつ特徴の全体像を明らかにするうえで、『1から始める Juliaプログラミング』にある説明が助けになる。以下に引用:

Juliaのおもな特徴をまとめると、以下のようになる。

  • オプショナルな型宣言、リッチな型システム、動的型付け

  • 多重ディスパッチと呼ばれる、引数の型の組合せに応じて関数の振舞いを定義できる仕組み

  • just-in-time (JIT) コンパイラLLVMバックエンドによる高速な実行

  • Lispのようなマクロやその他のメタプログラミング機能

  • Cなどの静的型付け言語に迫る速い実行速度

―進藤裕之・佐藤健太共著『1から始める Juliaプログラミング』(コロナ社

このうち第4章では型とその注釈、多重ディスパッチ、メタプログラミング機能について紹介されている。 第5章ではJITコンパイラLLVM、それに最適化の仕組みについて述べられていて、第6章では高速化に寄与するユーザーのプログラミングスタイルが解説されている。

第5章の冒頭ではFig. 8としてJITコンパイラの手順が書かれているが、これに対応する形で(微妙に異なるものの)『1から始める Juliaプログラミング』の図4.1が理解を助けてくれる。 もしくはACMウェブサイトの論文ページにある講演動画11:20くらいの投影スライドが参考になる。 型推論 (Type Inference)、関数のインライン化 (Method Inlining)、Object Unboxing(これは関数のインライン化とはどう異なるのだろう? 解読中)などの様々な処理が行われていることがわかる。

第6章では、ユーザーがどのようにJuliaでプログラミングをしているかがわかる。 それによれば、ほとんどの関数で引数に型注釈が付与されていて、また型安定 (Type Stability3) を実現するように書かれている。 多重ディスパッチの一例として、既存の機能を拡張するオーバーロードも活用されている様子が見て取れる。

関連する研究

第7章に対応、あとで追記予定

まとめ

プログラミング言語とはOSに備わっていて使うもの、普段はそういった意識でいるけれども、Rebuildエピソード206での森田さんの熱い語りを聴いていて、たまにはプログラミング言語開発者の気持ちになってみようと思い論文を読んでみた。

これまで見てきたように、Juliaの生産性と高速性能は巧みな言語設計と言語の実行、それにユーザー側の習熟によってもたらされているものである。 特に実行時のLLVMという概念は今回の論文で初めて知ったのだけれど、調べてみたらLLVMの作者はChris Lattnerということで、この彼はまさにRebuildエピソード206でSwiftの開発者として引き合いに出されていたのだった。不思議な繋がりがある。

Fortranで普段のプログラミングをしていると、強い静的型付けであることにそんなに違和感を覚えないのだけれど、それでも論文で挙げられていたようなJuliaの特徴を活かすことで生産性をもっと上げられるのかもしれない。 実行するマシン、ようはスーパーコンピューター側での事情もあり、大規模の問題を解くプログラムがすぐにJuliaに移行していく未来はやや想像しがたいものの、それでも一方に旧来のperformance languageとしてのFortranを携えつつ、もう一方にBOTH performance and productivity languageのJuliaも使えるようになれれば、それは理想的だなと思う。■


  1. Rebuildエピソード162では、室町時代から開発されている伝説のGPUの話題がありますが、それとは別物

  2. 論文が発行された2018年時点での話であって、現時点での状況は要調査

  3. Type Stabilityとは講演動画4:37あたりで解説されているように、型の不整合が想定されない状態と理解している