Fiber Schedulerの使い方
この記事では、Ruby3で追加される予定のScheduled Fiberを紹介します。Ruby 3.0.0 preview1の情報であり、この機能はまだまだ議論と開発の真っ只中です。実際に正式にリリースされるのものとはインターフェースや実装が異なることをご理解ください。
Ruby本体の事情にかなり疎いので、いろいろと想像で補っている部分があります。間違ったこと言っていたら教えてくださると助かります。
Fiber Scheduler
とは
Fiber Schedulerは、Ruby3で追加される予定の、Fiberの新機能です。IOを扱うファイバーを複数作って、これらを適切にコンテキストスイッチしてあげると、Threadを使うよりも高い並行性を得られるという話があります。Fiber Schedulerは、このコンテキストスイッチを実装しやすくするための機能で、もともとはAuto Fiberと呼ばれていました。
経緯
これらのチケットで議論されました。もともとAuto Fiberは、Ruby Coreの方で適切なコンテキストスイッチを提供してあげようという提案でした。紆余曲折あって、Fiberのブロッキング操作に対してフックできるインターフェースを提供しようという事になったようです。
- Feature #13618: [PATCH] auto fiber schedule for rb_wait_for_single_fd and rb_waitpid - Ruby master - Ruby Issue Tracking System
- Feature #14736: Thread selector for flexible cooperative fiber based concurrency - Ruby master - Ruby Issue Tracking System
Ruby 3.0 preview1にマージされたのはこのissueで作られたPRです。
PR
- Thread scheduler for light weight concurrency. by ioquatix · Pull Request #3032 · ruby/ruby · GitHub
- ]Scheduler by ioquatix · Pull Request #3434 · ruby/ruby · GitHub]
何がうれしいか?
Fiber Schedulerが開発された目的は、既存のコードをあまり変更せずに並行性を向上させることです。
Fiberを使ってIO待ちの間、うまいことコンテキストスイッチをしてやると、Threadよりも効率よく非同期処理ができる、という話があります。
IO待ちのファイバーを適切に切り替えて行けるSchedulerを実装しておくと、IO#reade, IO#writeなどのブロッキング処理を、Fiberの提供する軽量スレッドを使って非同期で実行できるようになります。 うまく行けば、既存のロジックを変更せず、Fiber.scheduleで囲むだけで、同時接続に対してスケールできます。
この機能を作っているSamuel Williamsさんによる説明があるので、英語がわかる方はこちらをどうぞ。 Ruby Concurrency Final Report
使い方
Schedulerを作り、Fiber.schedulerに非同期で実行したい処理を書きます。
Schedulerのインターフェースはこちらで定義されています。
このインターフェースを実装したクラスをThread.current.scheduler
に設定したうえで、Fiber.scheduleにブロックを渡すと、渡したブロックで実行されるブロッキング処理を行う際、Schedulerに実装されたメソッドをフックします。
class MyScheduler def io_wait(io, events, timeout) # 実装する end # 省略 end Thread.current.scheduler = MyScheduler.new Fiber. schedule do # この中身はMySchedulerによってコンテキストスイッチしながら非同期で実行される end
つかってみる
以前紹介していた、nio4rを使ってselectすることで、ノンブロッキング処理ができるSchedulerを作って使っています。 Fiberとnio4rでサーバー - まいおじ
これで一応動くんですが、acceptが動かなかったりするので、なにか間違えてるかもしれません。ソースコード読みながら何がおかしいか探っていく予定。