7

我正在编写一个 rake 任务,该任务每分钟(将来可能每 30 秒一次)被每当调用一次,它会联系一个轮询 API 端点(我们数据库中的每个用户)。显然,这作为单线程运行效率不高,但是可以多线程吗?如果没有,是否有一个很好的基于事件的 HTTP 库可以完成这项工作?

4

2 回答 2

13

我正在编写一个 rake 任务,该任务将由每当

注意 Rails 的启动时间,最好使用 Resque 或 Sidekiq 等分叉模型,Rescue 提供https://github.com/bvandenbos/resque-scheduler应该能够满足您的需要,我不能谈论 Sidekiq,但我确信它有类似的东西可用(Sidekiq 比 Resque 新得多)

显然,这作为单线程运行效率不高,但是可以多线程吗?如果没有,是否有一个很好的基于事件的 HTTP 库可以完成这项工作?

我建议您查看ActiveRecordfind_each以获取有关使您的查找过程更高效的提示,一旦您有了批处理,您就可以使用线程轻松地做一些事情,例如:

#
# Find each returns 50 by default, you can pass options
# to optimize that for larger (or smaller) batch sizes
# depending on your available RAM
#
Users.find_each do |batch_of_users|
  #
  # Find each returns an Enumerable collection of users
  # in that batch, they'll be always smaller than or 
  # equal to the batch size chosen in `find_each`
  #
  #
  # We collect a bunch of new threads, one for each
  # user, eac 
  #
  batch_threads = batch_of_users.collect do |user|
    #
    # We pass the user to the thread, this is good
    # habit for shared variables, in this case
    # it doesn't make much difference
    #
    Thread.new(user) do |u|
      #
      # Do the API call here use `u` (not `user`)
      # to access the user instance
      #
      # We shouldn't need to use an evented HTTP library
      # Ruby threads will pass control when the IO happens
      # control will return to the thread sometime when
      # the scheduler decides, but 99% of the time
      # HTTP and network IO are the best thread optimized
      # thing you can do in Ruby.
      #
    end
  end
  #
  # Joining threads means waiting for them to finish
  # before moving onto the next batch.
  #
  batch_threads.map(&:join)
end

这将启动不超过batch_size线程,等待每个线程batch_size完成。

可以做这样的事情,但是您将拥有无法控制的线程数量,您可能会从这里受益,它变得更加复杂,包括线程池和共享的工作列表,我已将其发布在 Github 上,以免向 stackoverflow 发送垃圾邮件: https ://gist.github.com/6767fbad1f0a66fa90ac

于 2012-10-07T11:28:57.250 回答
3

我建议使用擅长多线程的sidekiq。然后,您可以将每个用户的单独作业排入队列以轮询 API。发条可用于使您排队的工作重复出现。

于 2012-10-07T11:20:08.507 回答