Каждый поток должен работать независимо, и нет никаких тупиков с точки зрения доступа к данным.
Вы уверены в этом?
threads << Thread.new do
puts read(i)
end
Ваши темы делятся стандартным выводом. Если вы посмотрите на свой вывод, то увидите, что вы не получаете никакого чередующегося текстового вывода, потому что Ruby автоматически обеспечивает взаимное исключение на stdout, поэтому ваши потоки эффективно работают последовательно с кучей бесполезных конструкций / деконструкций / переключений тратить время.
Потоки в Ruby эффективны только для параллелизма, если вы вызываете какой-то контекст Rubyless *. Таким образом, виртуальная машина знает, что она может безопасно работать параллельно без взаимодействия потоков друг с другом. Посмотрите, что произойдет, если мы просто запишем вывод оболочки в потоках:
threads = Array.new(400) { |i| Thread.new { `echo Hello #{i}` } }
threads.each(&:join)
# time: 0m0.098s
против серийно
output = Array.new(400) { |i| `echo Hello #{i}` }
# time: 0m0.794s
* На самом деле, это зависит от нескольких факторов. Некоторые виртуальные машины (JRuby) используют собственные потоки и их легче распараллеливать. Некоторые выражения Ruby более параллельны, чем другие (в зависимости от того, как они взаимодействуют с GVL). Самый простой способ обеспечить параллелизм - это запустить одну внешнюю команду, такую как подпроцесс или системный вызов, обычно они не содержат GVL.