RE2JのFacebookからのissue
Facebookのオープンソース活動で、最初にこいつらなかなかいい奴らだな、と自分が思ったのは、RE2Jで見かけた時の事だったと思う。 RE2Jでbyte array使えないかなぁ、と思ってissueを眺めていたら、 Sliceという別のライブラリに依存した形で同じような事をやっていた。
Sliceはunsafeバリバリで低レベルにバイト列を効率的に扱うようなライブラリなので、 あまりJava的にお行儀が良い物では無い。 そんなものに依存したコード持っていっても取り込むのは嫌がる、というのはFacebookの人たちも分かっていたと思うけれど、 まず自分たちの問題を解決する事を優先したのだと思う。 そしてそれをどうやったか示すだけに留める、という姿勢。 手元の問題を解決する事を最優先とするハッカー気質を感じて、なかなかいいな、と思った。
このissueでGoogle側がなんのかんのと理由をつけて取り込まないくせに代替案も実現せず、結局公式ではbyte列は扱えないままなのが対照的で面白い。
なお自分は同じような機能が欲しかったが、AndroidにSlice持っていくのも大変だったので、このslice版をforkして機能削ってsliceとガワを揃えたbyte arrayの実装をでっちあげて使った。RE2Jのフルの機能は実現出来ないが、自分が使う分には問題無かったので、まぁいいか、と。Facebookとは友達になれそうなアプローチである。
Facebookのオープンソースは、使ってみると、要らない所は手を抜きつつ頑張って欲しい所は頑張っていて、こいつら分かってるなぁ、と思った。 プログラマの為のライブラリって感じがするんですよね、素人のお客様の為じゃなくて。我々の為にコードを公開している、という仲間意識を感じる。
そしてFacebookいいな、と思ったものでここで特に取り上げたいのはFollyです(今年読んだものでちょっと話しましたが)。
FollyにみるFacebookのハッカー的姿勢
Follyとは何かというと、Facebookが公開しているC++の基礎ライブラリ、と言えるだろうか。 FutureやBatonなどのちゃんとした並列プリミティブや、Arenaなどのデータ構造とかが全部ごちゃっと入っている。
一部だけ使うとかは出来なくて、全部入れる、という前提な所がモノレポカルチャーだなぁ、と思う。 また、例えばQtなどの他のフレームワークと混ぜよう、とかいうと、いろいろ困る所がある。 でも「サーバーサイドで使っている自分たちはそういう事は無かった」という姿勢なのだろう、と勝手に思っている。
使う人の視点からすると一部だけ欲しい、という事は結構あるのだけれど、そういう対応はしない。 必要な物だけ切り出して、不要な依存は排除して、thread poolはプラットフォームのものも使えるようにして…とかそういう事はしない。 自分たちの問題に最短でアプローチして、解決して、そしてそのノウハウを分かる人には分かる形で共有する。 かっこいい。
FacebookのFuture周辺の凄さ
現在C++以外の世界では、future-promiseという概念は広く使われていて、futureライブラリに期待される性質というのも、ほとんどコンセンサスが得られる段階にあると思う。(むしろちょっと今更感があるかもしれない)
昨今の多数のコアを使い切るには、小さな粒度で大量のfutureを作るスタイルが望ましい。 だから、大量のfutureを作ってもスレッド数がHWスレッド数以上に増えてしまわず、適当なスレッドプールで個々のfutureは低コストに実行される必要がある。 スレッドプールを使う為、ブロッキングで待ってスレッドを消費するのはまずいから、 全てノンブロッキングに結果を受け取って次のタスクをつなげていくスタイルで書く必要がある。 そして必要な時には特定の、例えばGUIスレッドなどで結果を受け取る必要もある。
信じがたい事だが、C++のfutureライブラリの多くは、この基本的な要求を満たしていない。 例えばSTLにはスレッドプールが無くて、executor的な概念も無いから、GUIスレッドで受け取る、みたいな事もうまく抽象化出来ていない。 futureが結果を受け取るのはwaitとか言ってブロックしてしまう。 当然スレッドを消費してしまうし、現代的なコア数がたくさんある環境でコア使い切るのにこれでは全然ダメだ。
FollyのfutureはGUIスレッドという実装は無いけれど、Executorとスレッドプール自体はあって、 どのExecutorで動かすか、という事がちゃんと指定出来る。 だからGUIスレッドのある環境で動かしたいとなれば、GUIスレッドのExecutorを書けば、GUIスレッドで結果を受け取る事もたぶん問題無い。 ちゃんと結果はノンブロッキングで待てて、 受け取るExecutorもちゃんと選べる。 こいつらちゃんとコア全部使ってんなぁ、というのが伝わってくるAPIになっている。
さらに実装を見るとスレッドプールもfutureも、 手抜きでロックしたくなるような所もatomicとかで頑張っていて、 メモリモデルの指定も細かい。 自分レベルでは全てが正しいのかは判断出来ないが、 すごい専門家っぽい人が頑張って書いたな〜って感じの実装になってて、いかにも早そう。 APIも分かっているが実装も分かっている。こいつら只者じゃない。 少なくとも私よりは大分腕が良い。やるなぁ。
Batonなどの並列primitiveも現代的で、エラーが少なく効率良く使えるような物がいろいろ用意されている。 彼らは本当にモダンな言語での現代の並列プログラムを良く分かってて、それをただ持ってくるだけでは無く、C++ではこうすべき、というアレンジもしつつ書いているように見える。 現代的な便利な発明をいろいろ理解しつつ、専門的なメモリモデルとかも最適な物で実装している。 Follyの並列すごい。
なお、並列以外も非常にC++14的な模範的なC++のコードになっていて勉強になるので、 C++を勉強するならFollyのコードを読むのは凄くオススメです。APIだけで無く実装も良い。 自分はまだ17使えない環境なので、14である事も嬉しい。