Конкурентность — это способ выполнения нескольких задач в перекрывающиеся периоды времени. В Ruby она реализуется особенным образом из-за GIL (Global Interpreter Lock).
threads = []
3.times do |i|
threads << Thread.new do
sleep rand(0.1..0.3)
puts "Поток #{i} выполнился"
end
end
threads.each(&:join)
fiber = Fiber.new do
puts "Первая часть"
Fiber.yield
puts "Вторая часть"
end
fiber.resume
fiber.resume
# Создаем рактор
ractor = Ractor.new do
Ractor.yield "Результат работы"
end
# Получаем результат
puts ractor.take
Пример с Async:
require 'async'
Async do |task|
3.times do |i|
task.async do
sleep rand(0.1..0.3)
puts "Задача #{i} выполнена"
end
end
end
require 'concurrent'
pool = Concurrent::FixedThreadPool.new(5)
10.times do |i|
pool.post do
puts "Обработка задачи #{i} в потоке #{Thread.current.object_id}"
end
end
pool.shutdown
pool.wait_for_termination
@counter = Concurrent::AtomicFixnum.new(0)
10.times.map do
Thread.new do
100.times { @counter.increment }
end
end.each(&:join)
puts @counter.value # => 1000
# Проблема
@value = 0
10.times.map do
Thread.new do
100.times { @value += 1 }
end
end.each(&:join)
puts @value # Может быть меньше 1000
mutex1 = Mutex.new
mutex2 = Mutex.new
Thread.new do
mutex1.synchronize do
sleep 1
mutex2.synchronize { puts "Поток 1" }
end
end
Thread.new do
mutex2.synchronize do
sleep 1
mutex1.synchronize { puts "Поток 2" }
end
end
Механизм | Лучше для | Особенности |
---|---|---|
Threads | I/O-bound задачи | GIL ограничивает CPU-операции |
Fibers | Легковесные задачи | Кооперативная многозадачность |
Ractors | CPU-bound задачи | Экспериментальный, Ruby 3+ |
Event Loop | Сетевые приложения | Асинхронный стиль программирования |
Резюмируем: Конкурентность в Ruby строится вокруг потоков с GIL, что делает её особенно эффективной для I/O-bound задач. Для CPU-bound операций рассматривайте Ractors или процессы. Используйте потокобезопасные структуры данных из concurrent-ruby для сложных сценариев. Понимание этих механизмов критически важно для создания масштабируемых Ruby-приложений.