Crystalは軽量スレッドを切り替えるためのランタイムスケジューラをもってる。少し調べてみた。
OSスレッドはカーネルのスケジューラによって切り替わるが、軽量スレッドはユーザが切り替えの責任をもつ。
spawn
で生成した軽量スレッドはsleep
を呼ぶことで別の軽量スレッドに明示的に処理を切り替えることができる。fiberで生成するだけではスケジューラの管理下にはおかれない。
spawn
の中でブロックする処理をかくと全てのタスクがブロックする。スケジューラはタスクをキューで管理していて、後から追加された軽量スレッドの処理からみていくが、
sleep
で明示的に切り替えを行った場合はlibevent2のタイマーによって処理が発火されるので実行順は不定となる。キューから取り出して実行したタスクが未完了だった場合に再びキューの末尾に追加する。
よく引き合いに出されるGolangのスケジューラとの違いでいえば、
そもそもN:Mスレッドモデルの上に構築されていない。なのでロックとかContext毎にrunqueueもつとかの実装もない。
単一のOSスレッド上でしか動作していないので、切り替わる処理を明示的に書かないといけない(GolangはOSのコンテキストスイッチだったりシステムコール呼び出しがトリガとなって実行Contextが切り替わる)
追記
作者の方からコメントをいただきました。
@yahhonob Nice! But I'd like to comment that Crystal isn't 1.0 yet, we plan to support multiple threads, the language is evolving…
— Ary Borenszweig (@asterite) 2015, 7月 22
やはり将来的にはマルチスレッド上で動かせるようにする計画があるようです。
今後に向けて楽しみですね!