我启动这个工作程序 10 次,以赋予它并发感:
class AnalyzerWorker
@queue = :analyzer
def self.perform
loop do
# My attempt to lock pictures from other worker instances that may
# try to analyze the same picture (race condition)
pic = Pic.where(locked: false).first
pic.update_attributes locked: true
pic.analyze
end
end
end
这段代码实际上仍然容易受到竞争条件的影响,我认为原因之一是因为获取未锁定的图片和实际锁定它之间存在时间间隔。
也许还有更多原因,有什么可靠的方法可以防止这种情况发生?
最佳答案
Active Record 提供乐观锁定和悲观锁定。
In order to use optimistic locking, the table needs to have a column called lock_version of type integer. Each time the record is updated, Active Record increments the lock_version column. If an update request is made with a lower value in the lock_version field than is currently in the lock_version column in the database, the update request will fail with an ActiveRecord::StaleObjectError.
Pessimistic locking uses a locking mechanism provided by the underlying database. Using lock when building a relation obtains an exclusive lock on the selected rows. Relations using lock are usually wrapped inside a transaction for preventing deadlock conditions.
引用链接中提供了代码示例...
两者都应该有效,但每个都需要不同的实现。从你所做的来看,我会考虑悲观锁定,因为发生冲突的可能性相对较高。
您当前的实现是两者的混合,但是,正如您所指出的,它确实不能解决问题。您也许可以让您的工作正常工作,但使用 Active Record 实现更有意义。
关于mysql - 如何防止多个worker竞相处理同一个任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19012123/