Безопасность данных и удаление GIL упоминает, что если у вас нет Giant Interpreter Lock на месте, вы повышаете риск состояния гонки. В блоге был приведен следующий пример:
# As noted in the blog post, this'll work correctly in MRI Ruby (1.8 or 1.9)
# but may or may not work correctly in Rubinius 2.0 or JRuby
@array, threads = [], []
4.times do
threads << Thread.new { (1..100_000).each {|n| @array << n} }
end
threads.each{|t| t.join }
puts @array.size
Один из подходов, который я бы выбрал, чтобы сделать поток кода безопасным, - это выполнять функциональное программирование и не иметь кода в потоке, изменять объекты / переменные, которые не были созданы в потоке:
threads = 4.times.map do
Thread.new do
sub_array = []
# Modifying sub_array is fine, because it was created by this thread
(1..100_000).each {|n| sub_array << n}
sub_array
end
end
puts threads.map(&:value).flatten(1).size
# Or (and don't forget nil!)
# array = threads.map(&:value).flatten(1) ; nil
# puts array.size
Можно ли указать, что потоку не разрешено изменять объекты / переменные, которые ему не "принадлежат", и выдать предупреждение или исключение, если это так?
Предположим, что многопоточный код не делает ничего особенно патологического, например, вызов ObjectSpace.each_object
.