--- title: ダイジェスト版「コルーチン」とは何だったのか tags: coroutine, lambdanote description: 『n月刊ラムダノート』創刊記念パーティーでの発表資料 --- # ダイジェスト版 『コルーチン』とはなんだったのか 2019/05/30 『n月刊ラムダノート』創刊記念パーティー https://hackmd.io/p/S1dw4Xy2V#/ https://hackmd.io/0j1gPlznSo6JBO0MloITfA# --- ## 自己紹介 * 遠藤侑介 @mametter * クックパッドで働くフルタイム Ruby コミッタ * Ruby 3 の静的検証とかテストまわりとか * コルーチンは Ruby コミッタになったきっかけ(の 1 つ) --- ## \[ruby-dev:30827\] ささだ 2007/05/28 > Continuation のついでに Fiber を入れました。 > (略) > というわけで、皆様にいくつかご相談です。おもに、名前と機能の話です。広くご意見を頂けると幸いです。 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/30827 --- ## \[ruby-dev:31596\] 遠藤 2007/08/22 > Fiber や Coroutine という言葉には、ちゃんとした定義もコンセンサスもないようなので、はっきりいって言ったもん勝ちです。 > (略) > 短くてかっこいいのを選べばいいと思います。 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/31596 --- ## コルーチンとは * 伝統的コルーチン(2000年代まで) * なんか制御構造みたいなやつ * 2 種類ある <!-- .element: class="fragment" data-fragment-index="1" --> * async function のこと(2010年代から) * 非同期処理を楽に書くやつ * 伝統的コルーチンとは完全に別物 <!-- .element: class="fragment" data-fragment-index="2" --> --- ## 対称コルーチン 元祖のコルーチン、`transfer` で実行を渡す ```ruby A = Fiber.new { # 2. A に実行が渡された → B に実行を渡す B.transfer() # 4. A に(再度)実行が渡された → 実行終了 } B = Fiber.new { # 3. B に実行が渡された → A に実行を返す A.transfer() # ここには到達しない } # 1. コルーチン A に実行を渡す A.transfer() ``` 単純だけど使いにくいので使われていない <!-- .element: class="fragment" data-fragment-index="1" --> --- ## 非対称コルーチン resume で起動(再開)、yield で中断 ```ruby A = Fiber.new { # 2. A が起動された → 中断して呼び出し元に処理を返す Fiber.yield() # 4. A はここから再開する → 終了して呼び出し元に処理を返す } # 1. コルーチン A を起動する A.resume() # 3. A が中断して帰ってきた → A を再開する A.resume() # 5. A が終了して帰ってきた → 実行終了 ``` 2000年代まではコルーチンと言えばコレだった <!-- .element: class="fragment" data-fragment-index="1" --> 無限列の実装に使える <!-- .element: class="fragment" data-fragment-index="2" --> --- ## async function async/await: 非同期処理を同期風に書く記法 ```javascript async function asyncABC() { await sleep(1000); print("foo"); await sleep(1000); print("bar"); } await sleep(1000); print("baz"); ``` ここでの「コルーチン」=`async function` <!-- .element: class="fragment" data-fragment-index="1" --> <span><!-- .element: class="fragment highlight-red" -->**伝統的コルーチンとは完全に別物!**</span> <!-- .element: class="fragment" data-fragment-index="2" --> --- ## 背景:JSの歴史的経緯 (1/4) 1990年代:関数は即時リターンする文化 * イベントを待つならコールバックを登録する * ~~主な用途:いたずら、ブラクラ~~ * みんな JS オフにしてた --- ## 背景:JSの歴史的経緯 (2/4) 2000年代:JavaScript アプリの複雑化 * Ajax, prototype.js, jQuery * 『コールバック地獄』の発生 * インデントが無限に深まっていく --- ## 背景:JSの歴史的経緯 (3/4) ES2015:非対称コルーチンと Promise の導入 * コールバック地獄を(理論上は)解決 * でも実際にはまだまだ書くのダルい * JS 民「非同期処理はコルーチンで!」 --- ## 背景:JSの歴史的経緯 (4/4) ES2017:async/await の導入 * わりとシンプルに書けるようになった * JS 界に平和が訪れた (?) * しかし…… --- ## あらたな用語地獄 * JavaScript コミュニティの一部でコルーチンと async function がやや混同されている * async/await を輸入した Python は async function を「コルーチン」と呼んだ * Kotlin は伝統的コルーチンも async function もまとめて「コルーチン」と呼んだ すでに別の意味で定着しつつある模様 --- ## まとめ みんなが愛した伝統的「コルーチン」は死んだ * 背景や文脈によって意味が異なる * 齟齬が生じないように注意しましょう