我正试图在MonogDB中实现这样的目标:
require 'base64'
require 'mongo'
class MongoDBQueue
def enq(thing)
collection.insert({ payload: Base64.encode64(Marshal.dump(thing))})
end
alias :<< :enq
def deq
until _r = collection.find_and_modify({ sort: {_id: Mongo::ASCENDING}, remove: true})
Thread.pass
end
return Marshal.load(Base64.decode64(_r["payload"]))
end
alias :pop :deq
private
def collection
# database, collection & mongodb index semantics here
end
end
当然,我想在Ruby中使用磁盘支持的队列,不会破坏我的可用内存,我使用的是Anemone web spider框架,它默认使用Queue
类,有一个fork可以使用SizedQueue
类,但是当对“页面队列”和“链接队列”使用SizedQueue
时,它通常会死锁,大概是因为它试图将页面出列并处理它,它是找到了新的链接,这种情况无法调和。
还有一个Redis队列的现有实现,但是这也耗尽了这台机器上所有可用的内存(可用内存为16Gb,所以它并非无足轻重)
因为我想使用这个MongoDB后端,但我认为实现是疯了。 Thread.pass
感觉像是一个可怕的解决方案,但Anemone是多线程的,MongoDB不支持阻塞读取,所以这是一个棘手的情况。
这是我的参考资料:
海葵的Redis队列实施:https://github.com/chriskite/anemone/blob/queueadapter/lib/anemone/queue/redis.rb
MongoDB findAndModify:http://www.mongodb.org/display/DOCS/findAndModify+Command
问题:
sleep
(无论如何应该触发VM将控制传递给下一个线程,但sleep
感觉更脏)相比,任何人都可以评论这是多么合理。Thread.pass
和sleep
吗? (我猜不是,见上文)答案 0 :(得分:0)
1)MongoDB中的读取是阻塞的。如果执行findOne()或findAndModify(),则在客户端存在数据之前,调用将不会返回。如果执行find(),则在获得游标之前调用将不会返回:您可以根据需要迭代游标。
2)默认情况下,对MongoDB的写入是&#34; fire and forget&#34;。如果您关心数据完整性,则需要通过设置安全写入:safe =&gt;在连接,数据库或集合对象中为true
答案 1 :(得分:0)
Kernel.sleep实际上是一个更好的解决方案,否则你将在那里旋转(尽管在每次查询后将控制传递给其他线程)。 由于findAndModify是原子的,只有一个线程(即使在JRuby上)也会接受这个工作,所以我不太明白这里的“阻塞”问题是什么。