Fibers
Ещё один механизм Ruby для реализации параллелизма - это волокна. Они запускают код из заданного блока. Волокна похожи на потоки. Главное отличие в том, что программист сам решает, когда запускать, приостанавливать и возобновлять волокна, в то время как потоки контролируются операционной системой. Это делает волокна более лёгкими и эффективными при переключении контекста. Кроме того, у потока может быть много волокон.
Волокна создаются с помощью блока Fiber.new { run someting; Fiber.yield; run again }, запускаются с помощью resume, приостанавливаются с помощью Fiber.yield (что переводит управление в точку возобновления волокна), возобновляются с точки приостановки и снова вызывают resume. Другой способ - метод transfer. Он передает управление выбранному волокну, которое затем возвращает его другому волокну.
fib2 = nil
fib = Fiber.new do
puts "1 - fib started"
fib2.transfer
Fiber.yield
puts "4 - fib resumed"
end
fib2 = Fiber.new do
puts "2 - control moved to fib2"
fib.transfer
end
fib.resume
puts "3 - fib paused execution"
fib.resume
# 1 - fib started
# 2 - control moved to fib2
# 3 - fib paused execution
# 4 - fib resumed
В Ruby 3.0 появилась концепция неблокирующих воркеров. Воркеры создаются по умолчанию с помощью опции blocking: false. Чтобы использовать эту функцию, необходимо настроить планировщик с помощью Fiber.set_scheduler(CustomScheduler.new). Класса Fiber::Scheduler не существует, он лишь описывает интерфейс реализации планировщика. Он должен реализовывать хуки для блокирующих операций (таких как ввод-вывод, ожидание, запросы к базе данных), которые вызывают Fiber.yield для приостановки воркера. Воркер возобновляется планировщиком, когда блокирующая операция завершается. Планировщик закрывается в конце текущего потока. Кроме того, Fiber.schedule запускает указанный блок в неблокирующем режиме.
В одном потоке может быть много воркеров, выполняющих более мелкие задачи. Воркеры, как и потоки, могут использовать преимущества Mutex, Queue, и SizedQueue при использовании в неблокирующем контексте.