Почему операция ‹< над массивом в Ruby не атомарна?

В Ruby этот код не является потокобезопасным, если array изменяется многими потоками:

array = []
array << :foo # many threads can run this code

Почему операция << не является потокобезопасной?


person Sławosz    schedule 20.07.2013    source источник


Ответы (5)


Фактически, используя MRI (реализация Matz Ruby), GIL (Global Interpreter Lock) делает любую чистую C-функцию атомарной.

Поскольку Array#<< реализован в MRI как чистый C-код, эта операция будет атомарной. Но учтите, что это относится только к МРТ. На JRuby это не так.

Чтобы полностью понять, что происходит, я предлагаю вам прочитать эти две статьи, в которых все очень хорошо объясняется:

Никто не понимает GIL
Никто не понимает GIL - часть 2

person Casper    schedule 20.07.2013
comment
К сожалению, ссылки мертвы - person Dennis; 13.01.2021
comment
@Dennis Спасибо за сообщение. Я заменил их ссылками Wayback Machine. Должно работать сейчас. - person Casper; 13.01.2021

Если у вас есть несколько потоков, обращающихся к одному и тому же массиву, используйте встроенный Ruby Queue класс. Он хорошо обращается с производителями и потребителями.

Это пример из документации:

require 'thread'

queue = Queue.new

producer = Thread.new do
  5.times do |i|
    sleep rand(i) # simulate expense
    queue << i
    puts "#{i} produced"
  end
end

consumer = Thread.new do
  5.times do |i|
    value = queue.pop
    sleep rand(i/2) # simulate expense
    puts "consumed #{value}"
  end
end

consumer.join
person the Tin Man    schedule 20.07.2013

array - это переменная вашей программы, когда вы применяете к ней операцию типа <<. Это происходит в три этапа:

  • Переменная сначала копируется в регистр ЦП.
  • ЦП выполняет вычисления.
  • ЦП записывает результат обратно в переменную память.

Таким образом, эта высокоуровневая однократная операция выполняется в три этапа. Между этими шагами из-за переключения контекста потока другой поток может прочитать то же (старое) значение переменной. Вот почему это не атомарная операция.

person Grijesh Chauhan    schedule 20.07.2013
comment
вы можете прочитать: Атомарные операции в Рубин - person Grijesh Chauhan; 21.07.2013
comment
ты это читал? Обновлено с комментарием Йорга за сентябрь 2011 г. - person Grijesh Chauhan; 21.07.2013
comment
@theTinMan Большое спасибо! мой английский плохой :( но я внимательно замечаю ваше и предыдущее редактирование моего ответа, я улучшу в следующем ответе. Спасибо! - person Grijesh Chauhan; 21.07.2013
comment
Это нормально. Никаких благодарностей не требуется. Это часть того, что мы отдаем сообществу. - person the Tin Man; 21.07.2013
comment
Это операция с массивом на C или сборка. В Ruby это также включает поиск методов, обработку аргументов и т. Д. - person Linuxios; 21.07.2013
comment
@GrijeshChauhan Array # добавление МРТ по крайней мере атомарно? правильно? jstorimer.com/blogs/workingwithcode/ - person chobo; 07.12.2018

Поскольку Ruby - это язык очень высокого уровня, на уровне ОС нет ничего атомарного. Только очень простые операции сборки являются атомарными на уровне ОС (зависят от ОС), и каждая операция Ruby, даже простая 1 + 1, соответствует сотням или тысячам выполненных инструкций сборки, таких как поиск методов, сборка мусора, инициализация объекта, вычисления области и т. Д. .

Если вам нужно сделать операции атомарными, используйте мьютексы.

person Linuxios    schedule 20.07.2013

Просто копирование @Linuxios и @TheTinMan: операции языка высокого уровня (HLL) в целом не атомарны. Атомарность (как правило) не является проблемой для однопоточных программ. В многопоточных программах вы (программист) должны рассуждать об этом с гораздо большей степенью детализации, чем отдельная операция HLL, поэтому наличие отдельных операций HLL, которые являются атомарными, на самом деле вам не так сильно. С другой стороны, хотя создание атомарной операции HLL требует всего нескольких машинных инструкций до и после, по крайней мере, на современном оборудовании, статические (двоичный размер) и динамические (время выполнения) накладные расходы складываются. Хуже того, явная атомарность в значительной степени отключает всю оптимизацию, потому что компиляторы не могут перемещать инструкции между атомарными операциями. Никакой реальной выгоды + значительные затраты = не началось.

person Amir Roth    schedule 22.07.2013