1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CrystalのFiberとスケジューラの仕組みを調べてみたのでメモ

Posted at

はじめに

CrystalのFiberのリスケジューリングがどう動いているのか気になって、軽く調べてみました。

といってもChatGPTを使って、Crystal本体のコードを読んでもらった結果をまとめたものですが、あとから簡単に振り返られるように記録に残したいのでQiita記事にします。

Fiberのコードを見る

まず、fiber.crを読んでみます。

fiber.cr

ここで、Fiberの実行はCrystal::Schedulerによって管理されていることが分かりました。そこで、次にscheduler.crを確認します。

scheduler.cr

調べてみると、**Fiber.swapcontext**で現在のFiberの実行コンテキストを保存し、別のFiberを再開する仕組みがあることがわかります。では、このswapcontextはどこに実装されているのでしょうか?

Fiberのコンテキスト切り替え

fiber/contextディレクトリに各プラットフォーム向けの実装が用意されています。

fiber
├── context
│   ├── aarch64.cr
│   ├── arm.cr
│   ├── i386.cr
│   ├── interpreted.cr
│   ├── wasm32.cr
│   ├── x86_64-microsoft.cr
│   └── x86_64-sysv.cr
├── context.cr
└── stack_pool.cr

x86_64-sysv.crは、Linuxで使用されるSystem V ABI用の実装です。ここでは、アセンブリを使ってレジスタやスタックを直接操作しています。

2つの重要な関数

  • makecontext:Fiberが最初に実行されるエントリーポイントをfiber_mainに設定します。
  • swapcontext:スタックポインタを切り替えて、現在のFiberから新しいFiberに実行コンテキストを移します。

低レベルの実装は理解困難ですが、ざっくりとこのような仕組みで動いていることが分かりました。

スタックプールの仕組み

次に、stack_pool.crについても確認します。

stack_pool.cr

ここでは、各Fiberごとに8 MiBのスタックメモリが割り当てられ、効率的に管理されています。スタックの再利用や解放を通じて、メモリの使用量を抑える仕組みになっています。

スケジューラが次のFiberを選ぶ仕組み

次に、Crystalのスケジューラがどのように次のFiberを割り当てるかを見ていきます。以下がrescheduleメソッドの実装です。

protected def reschedule : Nil
  loop do
    if runnable = @lock.sync { @runnables.shift? }
      resume(runnable) unless runnable == @thread.current_fiber
      break
    else
      Crystal.trace :sched, "event_loop" do
        @event_loop.run(blocking: true)
      end
    end
  end
end
  • 実行可能なFiberがある場合、キュー(@runnables)から取得してresumeで再開します。
  • 実行可能なFiberがない場合、@event_loop.run(blocking: true)が呼ばれ、次のイベントが発生するまでブロッキングされます。

EventLoopとlibeventの関係

@event_loopは、CrystalのEventLoopです。

event_loop.cr

Linuxでは、Crystal::LibEvent::EventLoopが使用されており、これはlibeventのバインディングです。

lib_event2.cr

libevent非同期IOタイムアウトを管理するC言語のライブラリで、Crystalはこの仕組みを使ってイベントを効率的に監視しています。

libeventは、Linuxでepollのようなシステムコールを使ってイベントを監視します。

CrystalのLibEvent2.event_base_loopは、イベントが発生するまで待機します。例えば、epoll_waitを使うことで、ソケットやファイルディスクリプタの状態変化を監視し、イベントが発生すると対応するFiberを再開します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?