Ruby Thread Pooling - 我做错了什么?

时间:2015-09-15 18:40:22

标签: ruby-on-rails ruby multithreading

我在Postgres数据库的Content表中有250万条记录,我需要遍历这250万条记录中的每一条并执行一些操作(其中许多都是自己很慢)并在最后更新记录根据我在路上收集的内容 - 一切正常 - 问题,这需要血腥的运行。

我遇到了几篇关于多线程这样的工作的文章(我之前在C中做过这个,但从来没有Ruby)和在Ruby中使用线程的优点和缺点,尽管有这些缺点,我可以得到2000个线程off比没有线程运行快得多,但我一次只能关闭2000,限制我实际上能够更新所有250万条记录。这是我的代码:

Content.all.each do |content|
  threads << Thread.new do
    grab_and_store(content)
  end
  index += 1
  index % 100 == 0 ? (puts index) : nil
end
threads.map(&:join)

我还读到了线程池,一旦完成了原来的工作,就使用相同的线程来完成其他工作,但我似乎无法让它工作。这是我的代码:

POOL_SIZE = 1000

jobs = Queue.new
Content.all.each{ |x| jobs.push x }

workers = (POOL_SIZE).times.map do
  Thread.new do
    begin
      while x = jobs.pop(true)
        grab_and_store(x)
      end
    rescue ThreadError
    end
  end
end
workers.map(&:join)

当我运行这个时,我得到一个错误,我无法在零级别上执行.join,这意味着工人在此结束时是零。但是,当我接受基于此的代码(如下所示,并source)并运行它完美无缺。我似乎无法弄清楚我的打破方式/如何最好地实现线程池以阻止我的代码在2000线程之后耗尽资源。

谢谢!

P.S。下面是我使用的教程中的代码:

require 'thread'
work_q = Queue.new
(0..50).to_a.each{|x| work_q.push x }
workers = (0...4).map do
  Thread.new do
    begin
      while x = work_q.pop(true)
        50.times{print [128000+x].pack "U*"}
      end
    rescue ThreadError
    end
  end
end; "ok"
workers.map(&:join); "ok"

更新

根据安东尼的回答,我发现自己使用了以下大块代码,使用他推荐的ruby-thread gem,它很快就完成了给定的内容(它的样本大小为1000),但是当我检查控制台时,它似乎只保存了大约20个。这是代码:

pool = Thread.pool(5)

@ids = []
arr = Content.where(needs_update: true)[0...1000]

puts "Starting With Sample 1000"

arr.each do |content|
  pool.process do
    grab_and_store(content)
  end
  index += 1
  index % 100 == 0 ? (puts index) : nil
end

pool.shutdown

1 个答案:

答案 0 :(得分:4)

我使用了ruby-thread gem来添加池支持,如下所示:

UINavigationBar