マイペースなRailsおじさん

Ruby、Ruby on Rails、オブジェクト指向設計を主なテーマとして扱います。だんだん大きくなっていくRuby on Rails製プロダクトのメンテナンス性を損なわない方法を考えたり考えなかったりしている人のブログです。

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のブロッキング操作に対してフックできるインターフェースを提供しようという事になったようです。

Ruby 3.0 preview1にマージされたのはこのissueで作られたPRです。

PR

何がうれしいか?

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でサーバー - まいおじ

gist.github.com

これで一応動くんですが、acceptが動かなかったりするので、なにか間違えてるかもしれません。ソースコード読みながら何がおかしいか探っていく予定。