正确的互斥使用/良好的编码风格?
在下面的代码中,生产者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
这是“好的”编码风格,还是有更优雅的方法?
谢谢!
Within the following code, the producer periodically_fill_page_queue might add a page to the queue that is currently being consumed (read: in the consumer before the status being_processed
is set).
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
To avoid this, i'd use a Mutex object:
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
Is this "good" coding style, or are there any more elegant approaches?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不是这个设计。一些替代设计可能会执行以下操作之一,但自然也有自己的麻烦。
“分叉”
对于每个作业,您启动一个新线程或进程,将作业
委托
给它,将任务委托给每个线程中的队列。每个线程都从自己独特的队列中拉取。
Stride
您有一个循环缓冲区,每个线程以不同的时间间隔进行检查。 EG
Num_threads + thread.id
这可能不适合你的情况。
范围
线程负责一系列作业。
num_threads * thread.id
这可能不适合你的情况。
Not with this design. Some alternative designs might do one of the below, but naturally have their own can of worms.
"Fork"
For each job you start a new thread or process, giving it the job
Delegation
Delegate the task to a queue in each thread. Each thread pulls from its own unique queue.
Stride
You have a circular buffer and each thread checks at a different interval. E.G.
Num_threads + thread.id
This probably isn't for your situation.
Range
A thread is responsible for a range of jobs.
num_threads * thread.id
This probably isn't for your situation.