Параллельные HTTP-запросы в ruby - PullRequest
10 голосов
/ 08 января 2012

У меня есть массив URL-адресов, и я не хочу открывать каждый из них и получать определенный тег.
Но я хочу сделать это параллельно.

Вот псевдокод того, что я хочу сделать:

urls = [...]
tags = []
urls.each do |url|
  fetch_tag_asynchronously(url) do |tag|
    tags << tag
  end
end
wait_for_all_requests_to_finish()

Если бы это можно было сделать красивым и безопасным способом, это было бы здорово.
Я мог бы использовать thread, но это не похоже на то, что массивы в ruby ​​безопасны для потоков.

Ответы [ 3 ]

32 голосов
/ 08 января 2012

Вы можете достичь безопасности потока, используя Mutex:

require 'thread'  # for Mutex

urls = %w(
  http://test1.example.org/
  http://test2.example.org/
  ...
)

threads = []
tags = []
tags_mutex = Mutex.new

urls.each do |url|
  threads << Thread.new(url, tags) do |url, tags|
    tag = fetch_tag(url)
    tags_mutex.synchronize { tags << tag }
  end
end

threads.each(&:join)

Однако использование нового потока для каждого URL может быть неэффективным, поэтому ограничениеколичество потоков, как это может быть более производительным:

THREAD_COUNT = 8  # tweak this number for maximum performance.

tags = []
mutex = Mutex.new

THREAD_COUNT.times.map {
  Thread.new(urls, tags) do |urls, tags|
    while url = mutex.synchronize { urls.pop }
      tag = fetch_tag(url)
      mutex.synchronize { tags << tag }
    end
  end
}.each(&:join)
9 голосов
/ 09 января 2012

Комбинация драгоценных камней Typhoeus / Hydra разработана для того, чтобы сделать это очень легко.Это очень удобно и мощно.

1 голос
/ 08 января 2012

Благодаря Ruby GIL это должно быть безопасно, основываясь на моем чтении http://merbist.com/2011/02/22/concurrency-in-ruby-explained/ и других ссылках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...