使用Rails运行多个后台并行作业

时间:2009-10-22 09:23:54

标签: ruby-on-rails ruby multithreading background

在我的Ruby on Rails应用程序上,我需要并行执行50个后台作业。每个作业都创建到不同服务器的TCP连接,定义一些数据并更新活动记录对象。

我知道执行此任务的不同解决方案,但它们中的任何一个并行。例如,如果只有并行执行所有作业,delayed_job(DJ)可能是一个很好的解决方案。

有什么想法吗?感谢。

3 个答案:

答案 0 :(得分:6)

实际上可以运行多个delayed_job worker。

来自http://github.com/collectiveidea/delayed_job

# Runs two workers in separate processes.
$ RAILS_ENV=production script/delayed_job -n 2 start
$ RAILS_ENV=production script/delayed_job stop

所以,从理论上讲,你可以执行:

$ RAILS_ENV=production script/delayed_job -n 50 start

这将产生50个进程,但是我不确定是否会建议这取决于你运行它的系统的资源。


另一种选择是使用threads。只需为每个作业生成一个新线程。

有一点需要注意的是,这种方法是ActiveRecord不是线程安全的。您可以使用以下设置使其成为线程安全的:

ActiveRecord::Base.allow_concurrency = true

答案 1 :(得分:1)

一些想法......

  • 仅仅因为您需要阅读50个网站并且自然需要一些并行工作而不是意味着您需要50个进程或线程。您需要平衡减速和开销。如果有10个或20个进程分别读取几个站点呢?

  • 根据您使用的Ruby,请注意绿色线程,您可能无法获得所需的并行结果

  • 您可能希望将其构建为反向客户端inetd,并使用connect_nonblockIO.select通过使所有服务器并行响应来获取所需的并行连接。您并不需要并行处理结果,只需要并行处理所有服务器,因为这是延迟的真正原因。

所以,来自套接字库的类似内容......将其扩展为多个未完成的连接......

require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(80, 'www.google.com')
begin
  socket.connect_nonblock(sockaddr)
  rescue Errno::EINPROGRESS
  IO.select(nil, [socket])
  begin
    socket.connect_nonblock(sockaddr)
    rescue Errno::EISCONN
  end
end
socket.write("GET / HTTP/1.0\r\n\r\n")
# here perhaps insert IO.select. You may not need multiple threads OR multiple
# processes with this technique, but if you do insert them here
results = socket.read

答案 2 :(得分:0)

由于您正在使用rails,我建议您使用delayed_job来执行此操作,而不是拆分为线程或分叉。原因是 - 在浏览器等待时处理超时和事情可能是一个真正的痛苦。 DJ可以采用两种方法

首先是 - 产生50多名工人。根据您的环境,这可能是一个非常重要的内存解决方案,但它工作得很好。然后,当您需要运行工作时,只需确保创建50个独特的工作。如果存在过多的内存膨胀,并且您希望以这种方式执行操作,请创建一个单独的环境,专门针对您的工作人员。

第二种方法是创建一个使用Curl :: Multi来运行50个并发TCP请求的作业。您可以在此处找到更多相关信息:http://curl-multi.rubyforge.org/这样,您可以让一个后台处理器并行运行所有TCP请求。