哪种Ruby的并发设备最适合这种情况?

时间:2014-10-25 11:17:51

标签: ruby

整个线程/纤维/处理事情让我感到困惑。我有一个可以通过一些并发解决的实际问题,所以我认为这是一个很好的机会,可以让专业人士和人们比我更了解它。

我有一个很长的阵列,让我们说3000项。我想为数组中的每个项发送一个HTTP请求。

实际上迭代数组,生成请求并发送它们非常迅速。需要时间的是等待我发送给的一方接收,处理和确认每个项目。我基本上发送100个字节,等待2秒,发送100个字节,等待2秒。

我想要做的是异步发送这些请求。我想发送请求,指定在收到响应时要执行的操作,同时发送下一个请求。

从我所看到的,我可以在这里使用四种并发选项。

  1. 线程。
  2. 纤维。
  3. 过程;据我所知,这是不合适的,因为访问同一阵列的多个进程是不可行/安全的。
  4. JavaScript等XMLHttpRequest
  5. 等异步功能

    最简单的似乎是最后一个。但是使用Ruby的最佳,最简单的方法是什么?

    失败的#4,剩下的三个中哪一个是最明智的选择?

    这些选项中是否还允许我说"任何时候都有不超过10个待处理请求"?

3 个答案:

答案 0 :(得分:2)

EventMachine作为事件循环和em-synchrony作为光纤包装器,用于回调同步代码

em-synchrony自述文件

复制粘贴
require "em-synchrony"
require "em-synchrony/em-http"
require "em-synchrony/fiber_iterator"

EM.synchrony do
  concurrency = 2
  urls = ['http://url.1.com', 'http://url2.com']
  results = []

  EM::Synchrony::FiberIterator.new(urls, concurrency).each do |url|
    resp = EventMachine::HttpRequest.new(url).get
    results.push resp.response
  end

  p results # all completed requests
  EventMachine.stop
end

答案 1 :(得分:2)

这是您经典的生产者/消费者问题,非常适合Ruby中的线程。只需创建一个队列

urls = [...] # array with bunches of urls
require "thread"

queue = SizedQueue.new(10) # this will only allow 10 items on the queue at once

p1 = Thread.new do 
  url_slice = urls.each do |url|
    response = do_http_request(url)
    queue << response
  end
  queue << "done"
end

consumer = Thread.new do
  http_response = queue.pop(true) # don't block when zero items are in queue
  Thread.exit if http_response == "done"
  process(http_response)
end
# wait for the consumer to finish
consumer.join

答案 2 :(得分:1)

这是一个IO限制案例,更适合两者:

  • 线程模型:在这种情况下MRI没有问题导致线程在IO情况下运行良好; GIL效果几乎为零。
  • 异步模型,证明(在实践和理论上)在涉及IO特定问题时远远优于线程。

对于这个特定的情况并且为了使事情变得更简单,我会使用Typhoeus HTTP客户端,它具有parallel支持,作为偶数(异步)并发模型。

示例:

hydra = Typhoeus::Hydra.new
%w(url1 url2 url3).each do |url|
  request = Typhoeus::Request.new(url, followlocation: true)
  request.on_complete do |response|
    # do something with response
  end
  hydra.queue(request)
end
hydra.run # this is a blocking call that returns once all requests are complete