ruby处理四个一组的数组元素

jexiocij  于 2023-06-22  发布在  Ruby
关注(0)|答案(5)|浏览(152)

我有一个ruby脚本数组,当每个元素需要处理时:

threads = []
elemets.each do  |element|
    threads.push(Thread.new{process(element)}}
end
threads.each { |aThread|  aThread.join }

然而,由于资源限制,如果一次不处理更多的四个元素,则脚本以最佳方式工作。
不,我知道我可以转储每个循环,并使用一个变量来计数4个元素,然后等待,但有没有一个更酷的Ruby方法来做到这一点?

bmp9r5qi

bmp9r5qi1#

您可以以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
u7up0aaq

u7up0aaq2#

如果我没看错的话,您希望一次处理不超过4个线程。
在我看来,你应该只启动4个线程,让它们都从一个共享队列(标准线程库的一部分)中读取数据来处理元素。
您可以在队列为空时让线程结束。
将数组分成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 }
kmpatx3s

kmpatx3s3#

rails(不是Ruby)中,可以使用更易读的形式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]

最后一行只有3个元素,因为我们在in_group_of中指定了false作为第二个参数。如果你想要nil或其他值,你可以用这个值替换false。

6jygbczu

6jygbczu4#

是的,但是你需要做一些方法覆盖。通常的方法是覆盖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]]
1qczuiv0

1qczuiv05#

不确定下面的变体是否只是使用“变量来计数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

相关问题