在以下代码中,生产者periodic_fill_page_queue可能会将页面添加到当前正在使用的队列中(读取:在设置状态being_processed
之前的消费者中)。
class Example
def initialize
@threads = ThreadGroup.new
@page_queue = Queue.new
Thread.abort_on_exception = true
end
def start
periodically_fill_page_queue
periodically_process_page_queue
end
def periodically_fill_page_queue
@threads.add(Thread.new do
loop do
if @page_queue.empty?
Page.with_state(:waiting).each do |p|
p.queued!
@page_queue << f
end
end
sleep 2
end
end)
end
def periodically_process_page_queue
loop do
until file = @page_queue.pop
sleep 2
end
page.being_processed
process(page)
end
end
def process(page)
sleep 120
page.processed
end
end
class Page < ActiveRecord::Base
state_machine :state, :initial => :waiting do
event :queued do
transition :waiting => :queued
end
event :being_processed do
transition :queued => :being_processed
end
event :processed do
transition :being_processed => :processed
end
end
end
为避免这种情况,我会使用Mutex对象:
def initialize
...
@mutex = Mutex.new
end
def periodically_process_page_queue
loop do
until file = @page_queue.pop
sleep 2
end
@mutex.synchronize { page.being_processed }
process(page)
end
end
这是“好”的编码风格,还是有更优雅的方法?
谢谢!
答案 0 :(得分:1)
不是这种设计。一些替代设计可能会做下面的一个,但自然有自己的蠕虫。
对于每个工作,您开始一个新的线程或流程,为其提供工作
将任务委派给每个线程中的队列。每个线程都从自己唯一的队列中拉出来。
您有一个循环缓冲区,每个线程以不同的间隔进行检查。例如。 Num_threads + thread.id
这可能不适合你的情况。
线程负责一系列工作。 num_threads * thread.id
这可能不适合你的情况。