八発白中

はてなブログに引越しました。

Day 19: clfreaks

これは fukamachi products advent calendar 2016 の19日目の記事です。

今日はclfreaksについて話します。今回はライブラリではありません。

コミュニティの規模

Common Lispのコミュニティサイズは絶望するほど小さくはありませんが、決して大きくはありません。

以前、佐野さんがGitHub Awardsの世界ランクトップの総スター数を比較すればおおよそのコミュニティ規模がわかるのではないかと言っていました。スターする人の多くはそのコミュニティに属する人だと予想できるので、正確ではなくともあながち間違った指標でもないかもしれません。

この指標で行くと、Common Lispの一位は僕の3040です。

Rubyの一位はHomebrewの75968、二位がthoughtbotの59813です。Homebrewはツールなのでコミュニティ外からのスターも含まれるかもしれませんが、それでもCommon Lispの20倍〜25倍強のコミュニティサイズがあります。

最近人気のGoはDockerの59126を一位として、GoogleGolang、Hashicorp、CoreOSなど有名企業が並んでいます。CLの20倍ほどのコミュニティサイズです。

Haskellはどうでしょうか。一位はjgmの9599です。他より小さいのは確かですが、これでもCLの3倍以上のコミュニティサイズです。

同じくらいの規模だと、D言語とかですね。それより小さい言語となるとStandard MLPascalなどになります。

こう比較するとCommon Lispのコミュニティがどれほど小さいかが実感できます。

コミュニティを大きくしたい

コミュニティの規模が小さいとできることが限られてきます。代表的な問題としてはライブラリが足りないとか、あってもメンテナンスされてないとか、十分に枯れてないとか、ドキュメントがないとか、そういうことです。そういったコミュニティでは何か作ったとしても誰も見てくれなければ承認欲求も満たされません。すると作り手も増えません。ライブラリは依然足りないままという悪循環。

そういうわけで、コミュニティを大きくするという課題はCommon Lispにはずっとあると僕は思っています。

Shibuya.lisp

そういう視点から言えばShibuya.lispが2008年からずっと定期的に開催され続けているというのは奇跡的かもしれません。一度運営が入れ替わり、運営方針がガラッと変わりました。3ヶ月に1回のお祭りイベントから、毎月開催のMeetupイベントへ。参加者も順調に伸びていて、発表者も毎回3人ほどいます。当初の「発表者がいない。集めるコストが高い」という問題も解決できているし素晴らしいことです *1

会員制クラブ「小田急CL」

自分はコミュニティ運営のようなマメなことは向いておらず、Shibuya.lispの運営メンバーに名を連ねてはいるものの全く手伝えていませんでした。

その頃、隔週くらいの頻度で自宅にCommon Lisperの友人たちを集めてハッカソンをやるということを始めました。

みんな多かれ少なかれオープンソース開発者なのでGitHubでどういうプロダクトを作っているとかはざっくりと知ってはいるのですが、それでも一堂に集まることには意味がありました。問題意識が共有できるし、苦手分野についてより詳しい人に直接質問したりできます。お互いのプロダクトを使い合うような間柄なので、もしIssueを上げるか迷っているような問題を抱えていたら相談もできます。プロダクト制作者としてはユーザーから直接意見を聞ける場でもあります。

毎回参加する顔ぶれはだいたい同じでした。僕の知り合いくらいの狭い範囲で集まっており、これも一種のコミュニティと言えるのではないでしょうか。参加するにはメンバーからの紹介が必要なので会員制クラブみたいなイメージかもしれません。

このコミュニティの名前は当初「小田急CL(仮)」でした。そのとき僕の自宅が向ヶ丘遊園駅の近くにあり、メンバーの3人が小田急沿線に住んでいたのでこの名前が(一時的に)つきました。

clfreaks

小田急CL」に名前が決まったかと思われたある日、僕の気まぐれで名前が「clfreaks」になりました。会場(僕の自宅)が場所を移しても違和感のない名前をつける必要があること、それからださい、っていうのが主な理由でした。

そうして始まったclfreaksのハッカソンですが、僕自身にはハッカソン以外にもやりたいことがありました。

clfreaksというのはShibuya.lispと違っていわゆるクローズドなコミュニティです。つまりは、そこで得られた知見などはメンバーしか知ることができないということです。

知識がインターネットで共有されることで価値を生むということを意義としていたWebプログラマの僕としてはクローズドなコミュニティはいただけません。情報をクローズドに保つのは健全ではないでしょう。

そういうわけで解決策としてハッカソンと並行して始めたのがPodcastでした。

Podcast

まあ聴く人なんてほとんどいないと思うけど、clfreaksでPodcastやってみようぜ、ってノリで始めたPodcastだったので終始雑な感じでした。

ただ、Podcastを始めてみて発見もありました。今までGitHubTwitterやブログなどでは伝えられなかったことが伝えられるようになっているという感覚です。

たとえば普段からCommon Lispを書いているメンバーが今何を課題と思っているのか、ってどれだけの人に伝わっているでしょうか。個々の完成物をGitHubや紹介ブログで見ることはできます。けれど、そのプロダクトがどういう背景で作られ、どういうストーリーを持って実アプリケーションに適応しうるのか、どういう優位性を持つのかなどはほとんど伝わっていないように感じます *2

clfreaksのPodcastはそのずばり解決になっていると思っています。音声データなので聴く人は限られるかもしれませんが、まあ全くないところからは一歩進歩です。

その後Quicklisp作者のZachに拾われたりしてそれなりに反響もありました。

twitter.com

この一年はほとんどお休みでしたが、また一段落したら集まってclfreaksを開催する予定です。

おわりに

clfreaksはTumblrで運用されており、Podcastで聞いたりWebページでMP3を直接聞けたりします。詳しくは以下のURLをご覧ください。

明日のアドベントカレンダーは20日目のDexadorについてです。お楽しみに。

*1:先月、運営に主に携わってくださっていた神田(potix2)さんやκeenさんから終了のお知らせがありました。それを残念がる声もありつつ、次期の運営として手を挙げてくださっている方も複数人いらっしゃるので、Shibuya.lispというのはまだ継続する可能性が高そうです。

*2:ちなみにこのアドベントカレンダーは、個々のプロダクトの背景を語ることで全体としての僕の課題意識とストーリーを知れるのではないかという試みから続いています。なので、それぞれのプロダクトの紹介というよりも作られたバックグラウンドストーリーなどが中心の内容になっています。

Day 18: trivial-signal

これは fukamachi products advent calendar 2016 の18日目の記事です。

今日はtrivial-signalについて話します。土日に細かいライブラリ紹介が並んでいるのはただの手抜きです。

Common LIspスクリプト

継続的なCommon Lispの課題として、スクリプトを書きづらいというものがありました*1

開発時はREPLなので問題にならないのですが、アプリケーションの起動などを考えればコマンドラインで起動できなければいけません。他のUNIXコマンドとの連携を考えてもCLIから離れられるわけではありません。

これは8日目に紹介したShellyで解決しようとした課題でもありますが、それでもまだその他の軽量プログラム言語ほどの手軽さはありませんでした。

その理由の一つがシグナルハンドリングでした。

POSIX シグナルハンドリング

シグナルハンドリングはUNIXでのプロセス間通信の方法の一つです。プロセスが特定のシグナルを受け取ったときにどうするかを指定しておけば他プロセスから制御することができます。

たとえば、スクリプトをターミナルで起動して、C-cを押すとINTが送られます。コマンドラインだとkill -INT <pid>のように送ることができます。

Common LispではPOSIX APIが仕様に含まれておらず *2、当然シグナルハンドリングもできません。C-cをするとSBCLではSB-SYS:INTERACTIVE-INTERRUPTというコンディションが発生できSIGINTのハンドリング自体はできますが、これでは2つ問題があります。

  1. 処理系依存である
  2. 他のシグナルはハンドリングできない

処理系可搬で、SIGINT以外のシグナルもハンドリングしたい。

それを解決するために生まれたのが「trivial-signal」です。

誰か作ってくれ

trivial-signalに関しては、他に誰か得意な人がやってくれたほうがいい、と当初から考えていました。あまり自分自身が使う機会も多くありません。とはいえ誰かが都合よく書いてくれるわけでもないので今必要な自分がとりあえず書く、けれどいつか誰かに引き継げるなら引き継ぎたいと思っていました。

名前に"trivial"と含まれるライブラリはAPIが自明の小さなライブラリがほとんどで、言ってしまえば標準ライブラリのような立ち位置の名前です。"Woo"や"Envy"のようなユニークな名前でなく、公共性の高い名前を敢えてつけたのは、やっぱりあまり思い入れがなくメンテナンスも頑張るつもりがなかったからでしょうかね。

ライセンスも珍しく"public domain"にしており、誰でも自由に使ってもらうようにしました。

浅井さん登場

そしてGitHubに置いてQuicklispに申請してほんの2ヶ月ほど。浅井さん(@guicho271828)からPull Requestを2つもらいました。

浅井さんと言えばCommon Lispやclfreaks界隈をウォッチしている人はご存知かもしれません。eazy-processなどGitHubでいくつかCommon Lispライブラリを公開しています。

Pull Requestをもらったとき、もはや早くもtrivial-signalの存在さえ忘れていました。この機会だから浅井さんにメンテナお願いしよーっとと思って声をかけます *3

深町: 実はこのライブラリあんまり使わないし、質を高く保てる自信ないんだよね。よかったらメンテしてくれない?
浅井: わかった

というような二つ返事であっさりメンテナを引き受けてくれました。ありがたし。

そういった経緯で、trivial-signalはこのアドベントカレンダーで紹介するライブラリで唯一僕がメンテナではありません。作者にあまり愛されずにドナドナされた不遇なライブラリだと思うとかわいそうなのでここで紹介して罪滅ぼしとします。

おわりに

trivial-signalはGitHubで公開されています。

明日のアドベントカレンダーは19日目のclfreaksについてです。お楽しみに。

*1:今ではRoswellスクリプトにより随分と快適になっている

*2:SBCLなど一部の処理系では処理系依存のパッケージとして提供している

*3:https://github.com/guicho271828/trivial-signal/pull/3

Day 17: smart-buffer

これは fukamachi products advent calendar 2016 の17日目の記事です。

今日はsmart-bufferについて話します。裏側で使っているライブラリなのでたぶん知らない人がほとんどかと思うので紹介です。

Wooの成功

15日目に話したWooは想像以上に受け入れられ、すぐに実際に使ってみようという人が多く見られました。そしていくつか質問も飛んできます。

よくあった質問がこれでした。「ファイルアップロードしたときにファイルが全部メモリに載ってるよね?大きいファイルアップロードしたらやばくない?」

twitter.com

大きなリクエストの保持方法

もちろん、全部メモリに載せてたら問題です。Wooではこの問題に対してスマートな方法で対処しています。

リクエスト本文を読み込んでいき、サイズが小さいうちはインメモリバッファにロードします。もしサイズがしきい値を超えたらバッファの内容をファイルに書き込み、ファイルバッファに切り替えます。

つまり、小さいリクエストのときはインメモリで高速に処理し、大きいリクエストはファイルに書き出してメモリ使用を抑えます。

twitter.com

元々fast-httpのmultipartパーサーの機能だったのですが、これは汎用的に使えるな、と思ってのちに別ライブラリにしました。それが「smart-buffer」です。

smart-bufferのアイデア

このアイデアは僕のオリジナルではありません。

Pythonmultipartというmultipart/form-dataのパーサーライブラリがあります。これが全く同じ仕組みで動作し、小さいファイルアップロードにはメモリで、大きいファイルアップロードにはディスクで対応しています。

おわりに

smart-bufferはGitHubで公開されており、Starは7です。使っているライブラリはfast-httpとWooだけですね。

明日のアドベントカレンダーは18日目のtrivial-signalについてです。お楽しみに。

Day 16: QURI

これは fukamachi products advent calendar 2016 の16日目の記事です。

今日はQURIについて話します。

PURIへの不満

Common LispにはURIを扱うライブラリとしてずっとPURIが使われていました。

僕も詳しい経緯は知らないのですが、元々Allegro CLにあったURIライブラリを処理系可搬にしたのがPURIのようです。元となったAllegro CLのURIライブラリはCopyrightが1998年からになっており、かなり古くからあるようですね。

古くからあり広く使われてきたからと言って、不満がないわけではありません。

最もよくある不満は、Unicode対応がないこと。PURIで、URLエンコードされているUnicode文字列をデコードすると文字化けするのです。

これだけならばURLデコードにPURIを使わなければいい、という話ですが、PURIはしかもそれをデフォルトでデコードするという意味のわからない仕様なのです。

puri-unicode

これに対して各自いくらかパッチを当てたりして使っていましたが、@archimag *1がPURIのUnicode対応版のpuri-unicodeを作ってそっとGitHubに置いていました。これが事の発端です。

するとそれを見つけた第三者が、puri-unicodeをQuicklispに入れてくれと申請を出します。

※以下は完全に意訳です。

HiTECNOLOGYs: puri-unicodeをQuicklispに入れて。
Zach: puri.asdが本家と競合するから入れられない。

それを聞いて今度は@archimagに「システム名がPURIと競合してるよ (ロシア語)」と送ります。

HiTECNOLOGYs: システム名がpuriと競合してるよ。
archimag: これはわざとだよ。puriはUnicode周りで問題がある。puriの代わりにpuri-unicodeをロードすればいい。
HiTECNOLOGYs: でもどうにかしてQuicklispに入れられないかな?
archimag: それはZachに言ってくれ。

という感じで全く話になりません。

Zach: 本家PURIにマージできたらいいと思うんだけど。
(一同): 確かに。
Andrew (Wookieの作者): メンテナにメールしてみました。返事ないです。

みたいなことを一年以上かけてやってるわけです。

通常、メンテナに連絡取れないときは新しいメンテナとなってマージしたものをQuicklispに置き換えて登録することが可能です *2。しかし出て来る人みんな非協力でどうにも進まない。まあ僕は何も手伝ってないので文句言える立場じゃないけど。

twitter.com

こういうことを半分本気でツイートしたんだけど、冗談と思われたのか意外とfavられずにタイムラインの底に沈みました。

Wooの副産物

そんなツイートも忘れて数ヶ月後のこと。Wookieの高速化やWooの開発などに没頭していた最中。

昨日の記事でWooを高速化する過程でURIパース部分にそれなりのボトルネックがあることがわかってきました。使っているライブラリはあのPURIです。

機能だけでなく速度にも問題がある。これは単純にUnicode対応すればいいという話ではなくなってきました。そういう経緯で、やっぱり自前で高速かつ高機能なURIライブラリを作る必要があろう、と考えました。

それが「QURI (キュウリ)」です。

QURI

QURIに求められていたのは、Wooで使うので可能な限り高速であること。PURIの代替機能をすべて持つこと。それからPURIに足りない機能を補完することです。

具体的に足りなかったのは以下です。

  • UTF-8対応
  • userinfo対応 (git@github.comgitの部分)
  • IPv6対応 (ldap://[2001:db8::7]/など)
  • URLエンコーダ・デコーダ
    • URIライブラリにまとめてしまうほうがわかりやすい
    • 別でいくつかライブラリがあったがどれも遅い

QURIではfast-httpで得た、高速なパーサを書く知見を活かしてURIをパースしました。つまりtagbodyとgoのオンパレードです。

最終的にURIパーサとしてはPURIより6.6倍高速にできました。

例によってRedditにも投稿されて議論されていました。「きゅうりってのはキューカンバーのことだよ」とか書いてあって面白いです。

DrakmaのQURI利用騒動

もはやPURIを使うモチベーションはなくなりました。僕の立場としてはPURIを問題のあるメンテナンスのされていないプロダクトとして喧伝し、PURIを使うプロダクトを減らしていく必要がありました。けれどWooの開発もあったのでなかなか宣伝して回るのも手が足りません。まず手始めに、僕のプロダクトでPURIをQURIに置き換えたりしていました。

そんなある日、僕の知らない間にCommon Lispの代表的なHTTPクライアントのDrakmaに「PURIをQURIで置き換える」というPull Requestが来て、トントン拍子でマージされました。

これによりDrakmaはUTF-8対応できました。Drakma自体は置換がうまくいったのです。けれど、Drakmaに依存する多くのライブラリが返り値としてPURIのオブジェクトが返ってくることを期待しているコードがあるようで、Quicklispの中に多くのライブラリが影響を受けて壊れたようです。そのためこのPull Requestはやむなくrevertされました。

メンテナンスはされていても広く使われていることで必要な改善もできずに朽ちていく過程です。

ちなみに僕はこの話の4ヶ月前にDexadorという新しいHTTPライブラリも作っています。こちらはもちろんfast-httpとQURIを使っており、Drakmaを置き換える新世代のライブラリを目指したものです。

Dexadorについては20日目に詳しくお話するので楽しみにしていてください。

おわりに

QURIはGitHubで公開されており、Starは44です。

明日のアドベントカレンダーは17日目のsmart-bufferについてです。お楽しみに。

*1:Andrey, RESTASの作者。https://github.com/archimag

*2:named-readtablesでは実際にそれが起きた

Day 15: Woo

これは fukamachi products advent calendar 2016 の15日目の記事です。

今日はWooについて話します。

これがあらすじです。

twitter.com

Wookieの高速化

Wookieのボトルネックを解消してもNode.jsのパフォーマンスには今一歩届かない。そこで使っているイベントライブラリのlibevent2が遅いのではないか?という疑念が生まれました。libevent2がボトルネックならば、libevや、Node.jsの使っているlibuvに切り替えることでNode.jsと対等に戦えます。

するとWookieの作者のAndrewが、libuvに切り替える予定だ、というリプライをくれました。

twitter.com

その頃、libuvとlibevent2の有効なベンチマークは知る限りありませんでした。しかし、Node.jsがlibevから乗り換えたことを考えるとlibuvもlibev程度は高速であることが見込めます。そしてベンチマークによってはlibevはlibevent2より2倍近く高速ということがわかっていました。

つまり、黙って見てるだけでも2倍近く高速になるかもしれないという状況です。

Wookieのスリム化

で、黙ってみているのもつまらない。その間にできることはやっておきましょう。

WookieにはWebサーバーとしては不要の機能がいくつかついていました。URLディスパッチャやプラグイン機構などがそうです。これらがプロファイリングには出てこずとも積み重なって有意な差を生んでいるかもしれません。

それを検証するために、余分な機能を削ぎ落としたバージョンを作ろうと考えました。そのサーバーがClack-compatibleなAPIを持つならばClackハンドラのボトルネックもありません。

そして完成したのが「Woo」でした。削ぎ落としたと言ってもフォークではなくスクラッチから書き直したのですが、2日程度で完成しました。

twitter.com twitter.com

ここで実験して得た知見をWookieにフィードバックしたいという程度のおもちゃのようなプロダクトでしたが、最初のバージョンでもはや少しNode.jsより高速になりました。

URIパースの高速化

また、何度かのWooのプロファイリングでURIのパース部分に時間がかかっていることがわかってきました。当時広く使われていたPURIというライブラリは遅くはなくとも十分に高速と言えるものではありません。

そこで「QURI」という高速なURIパーサーを書き、これをPURIと置き換えました。

twitter.com

QURIについては明日のアドベントカレンダー16日目で詳しく書く予定なので今回は割愛します。

サムライトに入社

河西くんに声をかけられたのはこの頃でした。彼は当時サムライトのCTOをやっており、Node.jsの広告配信サーバーを開発していました。個人的にはCommon Lispが好きだったにも関わらず、Common Lispが遅かったため、やむなくNode.jsで開発を行っていたのです。不幸な境遇です。

しかし、僕がCommon Lispは速いということをNode.jsとWooの比較で実証しました。1.2倍程度の差ではありますが、言語として比較してもJavaScriptより抽象度の高く開発効率も良いCommon Lispで書かない理由はもはやありません。

最初はCommon Lispへの移行を手伝う程度に考えていたのですが、話を聞いているうちに入社したほうがよかろうと思い、サムライトに入社することになりました。

サムライトに入社しても僕の仕事が大きく変わるわけでもありません。引き続きWooの高速化と安定化、他のWeb系ライブラリの開発、不具合や質問があれば迅速に対応するといったことが僕の仕事でした。

とはいえ、のんきにはしていられません。

サムライトは広告配信システムを開発しています。同時に大規模なリクエストがサーバーに飛んできます。つまりは思っていたよりも早くWooのパフォーマンスを試せる環境を得たわけで、これが対外的にCommon Lispの優位性をアピールできる舞台でもあるわけです。

このチャンスを逃すまいと、僕は一層Wooの高速化と安定化に励みました。

Wookieの脱落

そうこうしているうちにWookieの使っているcl-asyncのlibuv化が終わりました。

twitter.com

けれど、これは失敗でした。libuvにすることでWookieのパフォーマンスはがくっと下がり、もはやNode.jsどころかHunchentootにも負けるような状態になりました。

同じバックエンドを使っていたWooも当然パフォーマンスの劣化が見られました。けれど、それまでの十分なパフォーマンス向上により、なんとかNode.jsより1.3倍高速というラインを保っていました。とはいえここにきてのパフォーマンスの大幅な劣化は気分が沈みます。

僕は、Andrewがパフォーマンスが落ちるということを知りながら早急にmasterにマージしたのは失策だと思います。

当時の僕はcl-asyncのuvブランチの開発状況を確認しつつ、ベンチマークを取ってIssueでフィードバックしていました。そしていくつもの改善も虚しく結果は芳しくありませんでした。なのでパフォーマンスが落ちるということを知らなかったはずがありません。

libuvのほうが開発が活発だからその未来に賭けたいと思ったのかもしれません。けれど、パフォーマンスが重要なWebサーバーというプロダクトで、現状数十パーセントもパフォーマンスが劣化するならばそのコードはお蔵入りで当然でしょう。

せっかく苦労して書いたものを捨てるのは勿体ないと思ったのかもしれませんね。けれど、パフォーマンス・チューニングなんてそもそもそんなものです。速くなるかどうかはある程度コードを書いて動かしてベンチマークを取らなければわからない。結局遅ければ全部捨てて他の可能性を試す、ということの繰り返しです。

Wooの爆速化

Node.jsを圧倒的に引き離すにはもはや細かいチューニングではダメということは自明でした。数十パーセントの変化は設計上や基幹ライブラリなどを大きく変えるしかありません。

この頃から、Wooの安定化と並行して、libevへの移行を行いました。

libevならばlibevent2とのベンチマークも公式で出ており、2倍近くのパフォーマンス向上が見込めます。もはやライバルはNode.jsではなくGoに移りつつありました。

そしてcl-asyncからlibevバックエンドへの移行が完了しました。

twitter.com

移行により予想通りパフォーマンスは跳ね上がり、Node.jsの約1.9倍のパフォーマンスが出ており、Goに迫る勢いです。詳しくは当時のエントリーを御覧ください。

高速なCommon LispのWebサーバ「Woo」を作りました - 八発白中

ちなみに最新のベンチマーク結果では2.3倍のパフォーマンスが出ています。

f:id:nitro_idiot:20161215145356p:plain

反響1: 実アプリケーションでは遅いのでは

Common LispのWebサーバーがNode.jsより2倍近く高速で、かつGoに迫る勢いだ、という主張がベンチマークもついて公開されたというのはインパクトがあったのかもしれません。

Reddit*1HackerNews にも投稿され、それなりの反響がありました。

反響の中には驚きや賞賛も多かったですが、否定的なものも目立ちました。

その中でもよく目についたのが、「こんなHello, Worldを返すだけでは実際のアプリケーションとは言えない (からこのベンチマークは無効だ)」というものでした。

仰る通り。けれど、Wooは「Hello, Worldベンチマーク」に最適化したWebサーバーではありません。実環境でも当然ながらNode.jsよりは高速です。

これは僕の空想ではありません。その後サムライトでは1ヶ月を費やして広告配信システムをCommon Lispに書き換えて運用を始めました。

早期導入を優先したため、SQLの最適化などWebアプリケーション側のチューニングは十分に行わなかったにも関わらず、以前のNode.jsより1.6倍のパフォーマンスが出ています。

以下はEuropean Lisp Symbopium 2015で僕が発表したスライドの一つです。このスライドで会場から拍手をいただいたときは、やっぱりうれしかったですね。

f:id:nitro_idiot:20161215161421p:plain

Woo: Writing a fast web server @ ELS2015

反響2: 本当に最速?

もう一つあったのが、「teepeedee2を知ってるか?」というものでした。

teepeedee2とはJohn Fremlinの作った「10k requests / secを超えられる」という触れ込みのCommon LispのWebサーバーです。公開された2009年当時ではC10k問題への解決策としてかなり反響があったはずです。

John Fremlin's blog: teepeedee2 achieves 10k requests/second (キャッシュ)

ベンチマークグラフにはnginxも並んでいますが、そのnginxよりも1.5倍良いパフォーマンスを出しており、C++で書かれたWebサーバーに迫っています。

もちろんteepeedee2は知っています。けれども言ってしまえば、「teepeedee2はプロジェクトが死んでる」。

twitter.com

Quicklispには入っていますが、最新のSBCLではLinuxでもビルドできない状態になっています。

動かないものとベンチマーク比較しろって無理じゃないですか。

twitter.com

河西くんが調べてくれたところによると、CFFIのAPI変更によるものだろうということでした。そして親切なことに、彼は手元で動くように簡単に直してベンチマークを取ってくれました。その結果は残念ながら、Node.jsより少し遅い程度だったという平凡なものでした。

IOLibも高速だとよく聞きます。実はcl-asyncを一度IOLibで置き換えたこともありました。しかし、パフォーマンスは下がり、Node.jsより20%も遅かったです。

この辺りで「Common Lispは速い」と言っている人の中に盲信者が含まれていることに気づきました。実際のところ誰も何がどれくらい速いかなんてわかっていなかったのです。teepeedee2はリリース当時は確かに速かったのかもしれませんが、現在では他に追い抜かれて朽ち果てたプロジェクトとなっています。

Goに勝てる余地はあるのか

最近は「Goと比較してWooは少し遅いようだが、導入メリットはあるか」という質問をよくされます。はい、あります。

理由は利用言語の違いです。Common LispとGoを比較すればCommon Lispのほうが抽象度が高く、機能も豊富です。たとえばCLOSやコンディションシステムなどです。これは開発効率にも影響しますし、長期的にそれなりの規模のWebアプリケーションを運用していくならメリットは十分にあります。

今は、最近Goを使い始めたばかりという会社ばかりなのでチーム開発や長期運用面でのつらさなどは表に出てきていませんが、2年後、5年後、10年後にどうなっているのか少し楽しみです。

パフォーマンス面でWooはGoのサーバーに勝てるのか、という話であれば、まだわかりません。ただ打てる策はあります。libevをやめるということ。libevではなくpoll, epoll, kqueueのバインディングをそれぞれ作ってそれを呼び出せばまだ5%程度なら速くなる余地があります。

これをやらない理由は、現状でそこまでのパフォーマンスを求められていないということと、時間がないからという消極的な理由です。興味がある方はPull Requestは歓迎します。

おわりに

WooはGitHubで公開されており、Starは475です。これは僕のプロダクトの中ではClackに次ぐ2番目の評価です

明日のアドベントカレンダーは16日目のQURIについてです。お楽しみに。

*1:はてなブログRedditのURLが貼れないので見たい人はこちら。 ttps://www.reddit.com/r/programming/comments/2qio4m/woo_blazing_fast_http_server_in_common_lisp/