0

我启动这个工人 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

这段代码实际上仍然容易受到竞争条件的影响,我认为原因之一是因为在获取解锁图片和实际锁定它之间存在时间间隔。

也许还有更多的原因,有什么强有力的方法可以防止这种情况发生吗?

4

1 回答 1

0

Active Record 提供乐观锁和悲观锁。

为了使用乐观锁定,该表需要有一个名为 lock_version 的整数类型的列。每次更新记录时,Active Record 都会增加 lock_version 列。如果更新请求的 lock_version 字段中的值低于数据库中 lock_version 列中的当前值,则更新请求将失败并返回 ActiveRecord::StaleObjectError。

悲观锁定使用底层数据库提供的锁定机制。在建立关系时使用锁会在选定的行上获得排他锁。使用锁的关系通常包装在事务中以防止死锁情况。

参考链接中提供了代码示例...

两者都应该工作,但每个都需要不同的实现。从你正在做的事情来看,我会考虑悲观锁定,因为发生冲突的可能性相对较高。

您当前的实现是两者的混合,但是,正如您所指出的,它确实不能解决问题。你也许可以让你的工作,但使用 Active Record 实现是有意义的。

于 2013-09-26T05:30:42.853 回答