Ruby работает над элементами массива в группах по четыре
У меня есть массив ruby script, когда каждый элемент нуждается в обработке:
threads = []
elemets.each do |element|
threads.push(Thread.new{process(element)}}
end
threads.each { |aThread| aThread.join }
как бы из-за ограничений ресурсов, script работает оптимальным образом, если не более четырех элементов обрабатываются за раз.
нет. Я знаю, что могу сбрасывать каждый цикл и использовать переменную для подсчета 4 элементов, а затем ждать
но есть ли более холодный рубиновый способ сделать это?
Ответы
Ответ 1
Вы можете перечислять в группах по 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 утра, и у меня было всего пару часов сна.:/
Ответ 2
Если я правильно прочитаю, вы хотите иметь не более 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 }
Ответ 3
Не уверен, что следующий вариант учитывается как просто использование "переменной для подсчета 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
Ответ 4
Да, но вам нужно переопределить метод. Обычный подход состоит в том, чтобы переопределить '/' для 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]]
Ответ 5
В рельсах можно использовать более читаемую форму in_groups_of
arr= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
arr.in_groups_of(4, false) {|a| p a}
результат:
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11]