class 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.new 中创建,并设置 blocking: false(这是默认值),并且 Fiber.scheduler 应该通过 Fiber.set_scheduler 进行设置。如果在当前线程中未设置 Fiber.scheduler,则阻塞和非阻塞 fiber 的行为是相同的。

Ruby 不提供调度程序类:它期望由用户实现,并对应于 Fiber::Scheduler

还有一个 Fiber.schedule 方法,它期望以非阻塞的方式立即执行给定的块。其具体实现取决于调度程序。