Rails线程 - 多个任务

时间:2009-11-04 11:05:23

标签: ruby-on-rails thread-safety

我正在尝试运行多个任务,每个任务都访问数据库,我正在尝试将任务运行到单独的执行线中。

我玩过,试过我设置为true的allow_concurrency,或者config.thread_safe!但是我得到了不确定性的错误,例如有时一个类缺失,或者是一个常数......

这是一些代码

grabbers = get_grabber_name_list
threads = []
grabbers.each { |grabber|
  threads << Thread.new {
    ARGV[0] = grabber
    if (@@last_run_timestamp[grabber.to_sym].blank? || (@@last_run_timestamp[grabber.to_sym] >= AbstractGrabber.aff_net_accounts(grabber, "grab_interval").seconds.ago))
    Rake::Task["aff_net:import:" + grabber].execute
    @@last_run_timestamp.merge!({grabber.to_sym => Time.now})
  end
  }
}
threads.each {|t| t.join }

谢谢

2 个答案:

答案 0 :(得分:3)

我最近实现了一个使用线程的Rails应用程序并做了一些发现:

首先,如果您要在线程外部写入任何数组或哈希值(即复杂类型),请将它们包装在互斥锁中。它看起来像哈希和数组引用可能不是线程安全的。散列/数组元素索引似乎不太可能是线程安全的,但我所知道的是,在写入之前将外部数据结构放入互斥锁之后,问题就消失了。

其次,在线程终止时关闭ActiveRecord连接,否则最终可能会创建大量过时的连接。这是一个post about how to do this。我不知道它是否仍然适用于Rails版本&gt; 2.2但在我明确地开始关闭连接后,我的问题就消失了。作者建议猴子修补ActiveRecord自动执行此操作,但我决定在我的代码中明确释放连接。

这是一个适合我的代码示例:

mutex = Mutex.new
my_array = []
threads = []
1.upto(10) do |i|
  threads << Thread.new {
     begin
       do_some_stuff
       mutex.synchronize {
         # You'd think that each thread would only touch its own personal
         # array element but without a mutex, I run into problems.
         my_array[i] = some_computed_value
       }
     ensure
       ActiveRecord::Base.connection_pool.release_connection
     end
   }
}
threads.each {|t| t.join}

顺便说一下,如果你使用线程来利用多核CPU,你需要使用JRuby。据我所知,JRuby是唯一可以利用本机CPU线程的实现。如果您使用线程以便在等待网络连接或其他非CPU任务时可以执行其他操作,则这不是问题。

答案 1 :(得分:0)

你应该使用后台工作人员这样做。后台工作者库有几个选项,但我最喜欢的是delayed_job(http://github.com/tobi/delayed_job)。

将您发布的代码转换为后台作业应该非常容易。