ruby работает над элементами массива в группах по четыре
У меня есть массив скриптов ruby, когда каждый элемент нуждается в обработке:
threads = []
elemets.each do |element|
threads.push(Thread.new{process(element)}}
end
threads.each { |aThread| aThread.join }
как всегда из-за ограничений ресурсов, скрипт работает оптимальным образом, если не более четырех элементов обрабатываются одновременно.
нет я знаю, что могу сбросить каждый цикл и использовать переменную для подсчета 4 элементов, а затем ждать но есть ли более крутой рубиновый способ сделать это ?
4 ответа:
вы можете перечислить в группах по 4 для массива:
>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].each_slice(4) {|a| p a} [1, 2, 3, 4] [5, 6, 7, 8] [9, 10, 11, 12]
Так что вы можете попробовать что-то вроде
elements.each_slice(4) do | batch | batch.each do | element | threads.push(Thread.new{process(element)}} end (do stuff to check to see if the threads are done, otherwise wait ) end
Это может быть не то, что вам нужно, хотя - я был с 3 утра, и у меня было только несколько часов сна. :/
Если я правильно вас понял, вы хотите иметь не более 4 потоков обработки одновременно.
Мне кажется, что вы должны запустить только 4 потока, и все они читаются из общей очереди (часть стандартного потока lib) для обработки элементов.
вы можете иметь конец потока, когда очередь пуста.
нарезка массива на 4 равных массива и наличие каждого потока обработки 1/4 элементов предполагает, что каждый элемент обрабатывает в то же время. Если некоторые из них занимают больше времени, чем другие, некоторые из ваших потоков закончатся рано.
используя очередь, ни один поток не останавливается, пока общая очередь не будет пуста, поэтому я думаю, что это более эффективное решение.
вот рабочая программа, основанная на вашем коде, чтобы продемонстрировать:
require 'thread' elements = [1,2,3,4,5,6,7,8,9,10] def process(element) puts "working on #{element}" sleep rand * 10 end queue = Queue.new elements.each{|e| queue << e } threads = [] 4.times do threads << Thread.new do while (e = queue.pop(true) rescue nil) process(e) end end end threads.each {|t| t.join }
Не уверен, что следующий вариант считается просто использованием "переменной для подсчета 4 элементов" или может считаться классным, но он дает вам массив в срезах размером не более 4 элементов:
x = (1..10).to_a 0.step(x.size - 1, 4) do |i| # Choose one p x.slice(i, 4) p x[i, 4] end
Да, но вам нужно сделать какой-то метод переопределения. Обычный подход заключается в переопределении ' / ' для
Array
вот так:class Array def / len a = [] each_with_index do |x,i| a << [] if i % len == 0 a.last << x end a end end
и с этим определением теперь вы можете легко сделать:
foo = [1,2,3,4,5,6] foo / 2 # Result is [[1,2], [3,4], [5,6]]