类 Fiber

Fiber 是在 Ruby 中实现轻量级协作并发的原语。 基本上,它们是一种创建可以暂停和恢复的代码块的方法,很像线程。 主要区别在于它们永远不会被抢占,并且调度必须由程序员完成,而不是由虚拟机完成。

与其他无栈轻量级并发模型相反,每个 fiber 都带有一个堆栈。 这使得 fiber 可以在 fiber 块内从深层嵌套的函数调用中暂停。 请参阅 ruby(1) 手册页以配置 fiber 堆栈的大小。

创建 fiber 时,它不会自动运行。 而是必须使用 Fiber#resume 方法显式请求运行。 在 fiber 内运行的代码可以通过调用 Fiber.yield 来放弃控制,在这种情况下,它会将控制权返回给调用者(Fiber#resume 的调用者)。

在 yield 或终止时,Fiber 返回最后执行的表达式的值

例如

fiber = Fiber.new do
  Fiber.yield 1
  2
end

puts fiber.resume
puts fiber.resume
puts fiber.resume

产生

1
2
FiberError: dead fiber called

Fiber#resume 方法接受任意数量的参数,如果是第一次调用 resume,它们将作为块参数传递。 否则,它们将是调用 Fiber.yield 的返回值

示例

fiber = Fiber.new do |first|
  second = Fiber.yield first + 2
end

puts fiber.resume 10
puts fiber.resume 1_000_000
puts fiber.resume "The fiber will be dead before I can cause trouble"

产生

12
1000000
FiberError: dead fiber called

非阻塞 Fiber

非阻塞 fiber 的概念是在 Ruby 3.0 中引入的。 当一个非阻塞 fiber 遇到通常会阻塞 fiber 的操作(如 sleep 或等待另一个进程或 I/O)时,它会将控制权交给其他 fiber,并允许调度器处理阻塞并在可以继续时唤醒(恢复)此 fiber。

要使 Fiber 的行为像非阻塞 fiber,需要在 Fiber.new 中使用 blocking: false(这是默认值)创建,并且 Fiber.scheduler 应该使用 Fiber.set_scheduler 设置。 如果 Fiber.scheduler 未在当前线程中设置,则阻塞和非阻塞 fiber 的行为是相同的。

Ruby 不提供调度器类:它应该由用户实现,并对应于 Fiber::Scheduler

还有一个 Fiber.schedule 方法,该方法应该立即以非阻塞方式执行给定的块。 其实际实现取决于调度器。