Threads
Потоки в Ruby представляют собой легковесные единицы выполнения, которые позволяют выполнять несколько операций одновременно. Они могут быть полезны для выполнения задач, которые требуют много времени, таких как сетевые запросы или операции с файлами. Однако, важно понимать, что Ruby использует глобальную блокировку интерпретатора (GIL), что может ограничивать истинную параллельность.
Создание потоков
Для создания потока в Ruby используется класс Thread:
# создание нового потока
thread = Thread.new do
10.times { |i| puts "Thread #{i}" }
end
# ожидание когда потока закончит выполнение
thread.join
Синхронизация потоков
Синхронизация потоков имеет решающее значение в многопоточном программировании для предотвращения состояний гонки и обеспечения целостности данных. Библиотека Thread предоставляет встроенные механизмы синхронизации, такие как мьютексы (Mutex) и условные переменные, для координации доступа к общим ресурсам между потоками.
В следующем примере mutex.synchronize do ... end гарантирует, что блок кода внутри него будет выполняться только одним потоком одновременно, предотвращая одновременные изменения shared_resource.
mutex = Mutex.new
shared_resource = 0
# создание нескольких потоков
threads = 5.times.map do |i|
Thread.new do
mutex.synchronize do
shared_resource += 1
puts "Thread #{i}: Shared Resource = #{shared_resource}"
end
end
end
# ожидание когда все потоки закончат выполнение
threads.each(&:join)
Блокирующие операции
В многопоточной среде блокирующие операции могут существенно повлиять на производительность и скорость отклика нашего приложения. Понимание того, как работает блокировка и как с ней справляться, крайне важно для эффективного использования многопоточности.
Блокирующие операции - это задачи, которые не позволяют потоку выполняться до тех пор, пока не будет выполнено определённое условие или операция не будет завершена. К распространённым примерам блокирующих операций относятся:
- I/O operations: чтение из файла или запись в файл, сетевые запросы и запросы к базе данных
- Sleep operations: приостановка выполнения на указанное время
- Waiting for a resource: ожидание блокировки, семафора или другого примитива синхронизации, чтобы они стали доступны
Когда поток сталкивается с блокирующей операцией, он переходит в состояние ожидания. При неправильном управлении это может привести к снижению эффективности, поскольку другие потоки могут ожидать, пока заблокированный поток освободит ресурсы или выполнит свою задачу. В однопоточной среде блокирующие операции могут привести к остановке всей программы до завершения операции.
Перенос блокирующих операций в отдельные потоки позволяет основному потоку продолжать выполнять другие задачи.
threads = []
# Thread 1: Симуляция блокирующей операции
threads << Thread.new do
puts "Thread 1 started (blocking)"
sleep(5) # Симуляция вычисления
puts "Thread 1 finished (blocking)"
end
# Thread 2: Симуляция не-блокирующей операции
threads << Thread.new do
puts "Thread 2 started (non-blocking)"
3.times do |i|
puts "Thread 2: Iteration #{i + 1}"
sleep(1) # Симуляция вычисления
end
puts "Thread 2 finished (non-blocking)"
end
# ожидание когда все потоки закончат выполнение
threads.each(&:join)
# Thread 1 started (blocking)
# Thread 2 started (non-blocking)
# Thread 2: Iteration 1
# Thread 2: Iteration 2
# Thread 2: Iteration 3
# Thread 2 finished (non-blocking)
# Thread 1 finished (blocking)