0

我有一个执行一些长任务的 lib 类(“更新程序”),这个任务可以手动启动(在浏览器中)或每 2 小时启动一次(我已经实现了 gem,每 2 小时执行一次这个任务的计划)。

看到这些任务在数据库上做了很多工作,我认为可能会发生一些并发错误(例如,如果调用 when 尚未工作)。我说对了吗?

我想到了一个使用互斥锁的解决方案,我的 Updater 类有一个伪代码,如下所示:

module Updater
  def start
    #do some job
  end
end

我认为一个正确的解决方案是这样的

module Updater
  def start
    mutex.lock
       #do some job
    mutex.unlock
  end
end

我的解决方案正确吗?

请提供更多关于并发的信息(例如如何在 Rails 中正确使用互斥锁,我必须要求什么等)?我已经搜索过,但没有找到任何很好的解释。

4

1 回答 1

1

我认为使用Ruby Mutex的正确方法是获得一个锁,运行一个代码块,然后再次释放锁,即结合解锁调用锁......

@mutex = Mutex.new
..

def start
  @mutex.lock
  begin
    ..
  ensure
    @mutex.unlock rescue nil
  end
end

或使用同步方法:

@mutex = Mutex.new
..

def start
  @mutex.synchronize do
    # do something
  end
end

可以在机架中间件类Rack::Lock中找到一个示例。但是我不确定它是否对您有帮助,即使您使用诸如 之类的类变量@@mutex,因为互斥量/信号量可能不会在不同任务和不同进程之间保留(我假设“任务”是由“rake”启动的不同进程任务”)。Mutex 类对于实现线程安全很有用,因为它实现了一个简单的信号量,可用于协调对来自多个并发线程的共享数据的访问。然而,还有一个关于线程安全的不错的 RailsCast(不幸的是只在付费墙后面)。

在您的情况下,它可能有助于在数据库中创建一个全局锁定标志,或者在文件系统中创建一个全局锁定文件,并在进程结束时touch lock.txt再次删除它。可以使用 Kernel.system 或 %x在 Rubyrm lock.txt中执行这些shell 命令。如果文件存在File.exists?("lock.txt"),则可以暂停更新。

于 2013-01-02T13:15:15.630 回答