Да, это работает. Только из-за этого использование потоков в MRI действительно полезно для многих рабочих нагрузок, хотя только один поток может одновременно выполнять «код».
Типичным примером является веб-приложение, такое как приложение Rails. Здесь вы можете запустить несколько потоков, например, с помощью Puma, в одном процессе, каждый из которых обрабатывает один запрос. Поскольку вы часто ждете базу данных здесь, может выполняться другой поток. Это работает, потому что адаптер базы данных (например, mysql2
или pg
) освобождает GIL при вызове базы данных и повторно получает его, как только ответ приходит и доставляется вызывающей стороне.
С помощью Mutex, однако, вы гарантируете, что определенный блок кода выполняется только одним потоком за раз. Типичным примером является сумматор:
class Adder
attr_reader :number
def initialize
@number = 0
end
def add(number)
new_number = @number
new_number = new_number + number
@number = new_number
# The above code is extremely verbose to show what's happening here.
# It is equivalent to
# @number += number
end
end
Здесь метод Adder#add
не сохраняет потоки. Если несколько потоков попытаются одновременно добавить числа, некоторые обновления будут потеряны, так как операция не атомарна c (но состоит из чтения, операции и записи). С Mutex около add
вы можете убедиться, что операция завершается в одном потоке, а общие структуры данных обновляются последовательно.
В качестве общего совета, вы всегда должны использовать Mutex, если вы читаете или обновляете любые данные, разделяемые через границы потоков. Чтобы гарантировать правильность, вы также должны строго контролировать, какие структуры данных передаются через границы потоков, и избегать этого, если это возможно.
Если вам все еще это необходимо, гем 1011 * concurrent- ruby предоставляет некоторые Потокобезопасные структуры данных, которые могут помочь с обменом данными через границы потоков.