假设我有200个昂贵的方法调用(每个都有不同的参数)。出于某种原因,我可以并行执行其中5个调用,但不能再执行。我可以一次执行一个,但每次执行5次的速度要快5倍。
我想永远执行五件事。我不想排队五,等到所有五个完成,然后排队五个。如果我排队A,B,C,D,E和C先完成,我想立即用F替换它,即使A和B还没有完成。
我一直在阅读这个问题,因为这是我可以想象的定期发生的事情。解决方案似乎是生产者 - 消费者模式,Ruby在其标准库中内置了一些结构,用于该模式(Queue
和SizedQueue
)。我玩过代码示例,阅读了一些文档,我想我对它有一个粗略的了解。但我有一些问题,我对我的解决方案并不自信,而且多线程的整个领域对我来说都是新的基础,所以我想我会在这里要求确保我不是,你知道,完全错了,只是幸运
所以这是我写的测试程序:
q = Queue.new
q << 'balloon'
q << 'sandwich'
q << 'clown'
q << 'fairy floss'
q << 'ferris wheel'
q << 'magician'
q << 'cake'
q << 'present'
q << 'chip'
q << 'game'
q << 'animal'
consumer_1 = Thread.new do
until q.empty?
sleep rand(0..10)
print "#{q.pop}\n"
end
end
# consumer 2 and 3 are identical to consumer 1
[consumer_1, consumer_2, consumer_3].map(&:join)
队列中包含生日聚会所需的一系列内容。 3个消费者线程在列表中工作。
这有效,我的问题是:
如果消费者的数量决定了并行工作的项目数量,那么拥有大小的队列有什么意义呢?
大小的队列是否仅在任务无限,未知或数量巨大并且您想在填充队列之前暂停的情况下才有用?
我未能正确解决问题吗?手动创建多个线程然后在它们上面调用join
似乎有些混乱。有更好的解决方案吗?
答案 0 :(得分:1)
SizedQueue可以防止生产者更快地添加商品,然后消费者可以消费。
<强> SizedQueue#push 强>
如果队列中没有剩余空间,则等待空间变为空间 可用
如果队列为空,则调用线程将暂停,直到数据为止 推到队列上。
SizedQueue vs Queue
require 'thread'
require 'logger'
queue = SizedQueue.new(3)
#queue = Queue.new # goes berzerk
logger = Logger.new(STDOUT)
Thread.new do
item = 0
loop do
item += 1
queue << item
logger.info "#{item} produced"
end
end
consumers = 2.times.map do |i|
Thread.new do
loop do
item = queue.pop
logger.info "consumed #{item}"
sleep item
end
end
end
consumers.each(&:join)
如何停止工作线程
require 'thread'
require 'logger'
queue = Queue.new
logger = Logger.new(STDOUT)
consumers_count = 5
end_object = BasicObject.new
consumers = consumers_count.times.map do
Thread.new do
until (item = queue.pop) == end_object
logger.info "consumed #{item}"
end
end
end
1000.times.each { |item| queue << item }
consumers_count.times { queue << end_object }
consumers.each(&:join)
进一步阅读: