在Java中,有一个名为ArrayBlockingQueue的类作为其并发包的一部分。它是一个线程安全的类,您可以在其中添加和删除队列中的项目,而不必担心线程安全。此类有一个put
方法,允许您将项目放入队列。并且take
方法从队列中删除项目。关于put
和take
的两件好事是不需要synchronized关键字来进行线程交错的同步,并且take
耐心地等待直到某些东西被添加到队列中,而不是抛出一个如果没有任何内容则例外。
我尝试在ruby中实现类似的东西,但问题是queue.pop
似乎阻止了将项目添加到队列中(至少对于其中一个队列),如下所示:
require 'redis'
require 'date'
def log_debug(str)
debug_str = "#{DateTime.now} #{str}"
puts debug_str
end
class EmailsmsResponder
def initialize
@queue = Queue.new
end
# add to queue
def produce(channel, msg)
@queue << {channel: channel, msg: msg}
puts "queue size: #{@queue.size}"
end
# take from queue
def consume
loop do
log_debug "Whats going on??"
sleep(1)
if !@queue.empty?
item = @queue.pop
log_debug "removing channel #{item[:channel]} and msg #{item[:msg]} from email-sms thread from queue"
end
end
end
end
class SidekiqResponder
def initialize
@queue = Queue.new
end
def produce(channel, msg)
@queue << {channel: channel, msg: msg}
puts "queue size: #{@queue.size}"
end
def consume
loop do
log_debug "Whats going on??"
sleep(1)
if !@queue.empty?
value = @queue.pop
log_debug "removing channel #{item[:channel]} and msg #{item[:msg]} from sidekiq thread from queue"
end
end
end
end
class RedisResponder
def initialize(host,port)
@host = host
@port = port
@email_sms = EmailsmsResponder.new
@sidekiq = SidekiqResponder.new
# timeout so we wait for messages forever
@redis = Redis.new(:host => @host, :port => @port, :timeout => 0)
end
def start_producers
thread = Thread.new do
@redis.subscribe('juggernaut') do |on|
# message block fired for new messages
on.message do |channel, msg|
log_debug "New message"
@email_sms.produce(channel, msg)
@sidekiq.produce(channel, msg)
end
end
end
end
def start_consumers
thread = Thread.new do
@email_sms.consume
@sidekiq.consume
end
end
end
responder = RedisResponder.new('127.0.0.1', 6379)
responder.start_producers.join(responder.start_consumers.join)
当一个队列似乎正常工作时,另一个队列永远不会检索任何内容:
$ ruby redis-client4.rb
2014-07-22T14:53:24-04:00 Whats going on??
2014-07-22T14:53:25-04:00 Whats going on??
2014-07-22T14:53:25-04:00 New message
queue size: 1
queue size: 1
2014-07-22T14:53:26-04:00 removing channel juggernaut and msg {"channels":["/reports/6561/new"],"data":"New reports for unit 6561"} from email-sms thread from queue
2014-07-22T14:53:26-04:00 Whats going on??
2014-07-22T14:53:27-04:00 Whats going on??
2014-07-22T14:53:28-04:00 Whats going on??
2014-07-22T14:53:28-04:00 New message
queue size: 1
queue size: 2
2014-07-22T14:53:29-04:00 removing channel juggernaut and msg {"channels":["/reports/6561/new"],"data":"New reports for unit 6561"} from email-sms thread from queue
2014-07-22T14:53:29-04:00 Whats going on??
2014-07-22T14:53:30-04:00 Whats going on??
2014-07-22T14:53:31-04:00 Whats going on??
2014-07-22T14:53:31-04:00 New message
queue size: 1
queue size: 3
2014-07-22T14:53:32-04:00 removing channel juggernaut and msg {"channels":["/reports/6561/new"],"data":"New reports for unit 6561"} from email-sms thread from queue
2014-07-22T14:53:32-04:00 Whats going on??
2014-07-22T14:53:33-04:00 Whats going on??
2014-07-22T14:53:34-04:00 Whats going on??
2014-07-22T14:53:34-04:00 New message
queue size: 1
queue size: 4
2014-07-22T14:53:35-04:00 removing channel juggernaut and msg {"channels":["/reports/6561/new"],"data":"New reports for unit 6561"} from email-sms thread from queue
2014-07-22T14:53:35-04:00 Whats going on??
2014-07-22T14:53:36-04:00 Whats going on??
2014-07-22T14:53:37-04:00 Whats going on??
2014-07-22T14:53:37-04:00 New message
queue size: 1
queue size: 5
我可能做错了什么?
答案 0 :(得分:0)
我尝试在ruby中实现类似的东西,但问题是 即使将项目添加到队列
,queue.pop似乎也会阻止
这很容易被反驳:
require 'thread'
q = Queue.new
q << 'hello'
x = q.pop
puts x
x = q.pop
--output:--
hello
deadlock detected (fatal)
我可能做错了什么?
开始删除代码并简化操作以查明问题发生的位置。事实上,你有两个完全相同的课程意味着你甚至没有开始简化。
然后有这个:
def consume
loop do
log_debug "Whats going on??"
sleep(1)
value = queue.pop
log_debug "removing channel: #{channel} msg: #{msg} of sidekiq thread from queue"
end
end
***Error in `consume': undefined local variable or method `queue'
答案 1 :(得分:0)
我使用下面的代码。我不喜欢我必须使用4个线程才能让它工作,所以如果有人有更好的解决方案,我很乐意推荐他们的解决方案。但这似乎现在正在起作用:
require 'redis'
require 'date'
def log_debug(str)
debug_str = "#{DateTime.now} #{str}"
puts debug_str
end
class EmailsmsResponder
def initialize
@queue = Queue.new
end
# add to queue
def produce(channel, msg)
@queue << {channel: channel, msg: msg}
puts "queue size: #{@queue.size}"
end
# take from queue
def consume
loop do
log_debug "Whats going on??"
sleep(1)
if !@queue.empty?
item = @queue.pop
log_debug "removing channel #{item[:channel]} and msg #{item[:msg]} from email-sms thread from queue"
end
end
end
end
class SidekiqResponder
def initialize
@queue = Queue.new
end
def produce(channel, msg)
@queue << {channel: channel, msg: msg}
puts "queue size: #{@queue.size}"
end
def consume
loop do
log_debug "Whats going on??"
sleep(1)
if !@queue.empty?
item = @queue.pop
log_debug "removing channel #{item[:channel]} and msg #{item[:msg]} from sidekiq thread from queue"
end
end
end
end
class RedisResponder
def initialize(host,port)
@host = host
@port = port
@email_sms = EmailsmsResponder.new
@sidekiq = SidekiqResponder.new
# timeout so we wait for messages forever
@redis = Redis.new(:host => @host, :port => @port, :timeout => 0)
end
def start_producers
thread = Thread.new do
@redis.subscribe('juggernaut') do |on|
# message block fired for new messages
on.message do |channel, msg|
log_debug "New message"
@email_sms.produce(channel, msg)
@sidekiq.produce(channel, msg)
end
end
end
end
def start_consumers
thread = Thread.new do
t1 = Thread.new { @email_sms.consume }
t2 = Thread.new { @sidekiq.consume }
t1.join(t2.join)
end
end
end
responder = RedisResponder.new('127.0.0.1', 6379)
responder.start_producers.join(responder.start_consumers.join)