我有一个充满 URL 的数据库,我需要定期测试 HTTP 响应时间。我希望有许多工作线程始终为最近未测试的 URL 梳理数据库,如果找到,请对其进行测试。
当然,这可能会导致多个线程从数据库中获取相同的 URL。我不想要这个。所以,我正在尝试使用互斥锁来防止这种情况发生。我意识到在数据库级别还有其他选项(乐观锁定、悲观锁定),但我至少更愿意弄清楚为什么这不起作用。
看看我写的这个测试代码:
threads = []
mutex = Mutex.new
50.times do |i|
threads << Thread.new do
while true do
url = nil
mutex.synchronize do
url = URL.first(:locked_for_testing => false, :times_tested.lt => 150)
if url
url.locked_for_testing = true
url.save
end
end
if url
# simulate testing the url
sleep 1
url.times_tested += 1
url.save
mutex.synchronize do
url.locked_for_testing = false
url.save
end
end
end
sleep 1
end
end
threads.each { |t| t.join }
当然这里没有真正的 URL 测试。但最终应该发生的事情是,每个 URL 的“times_tested”应该等于 150,对吧?
(我基本上只是想确保互斥锁和工作线程心态正常工作)
但是每次我运行它时,这里和那里的一些奇怪的 URL 最终都以 time_tested 等于一个低得多的数字,比如 37,并且locked_for_testing 冻结为“true”
现在,据我从代码中可以看出,如果任何 URL 被锁定,则必须解锁。所以我不明白一些 URL 是如何像那样“冻结”的。
没有例外,我尝试添加开始/确保,但它没有做任何事情。
有任何想法吗?