2012-01-08 2 views
7

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

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

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

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

ответ

25

Вы можете достичь потокобезопасности с помощью 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) 
+0

Ха-ха, это было то же самое решение, которое я написал! :) –

+0

Если основная часть работы IO, количество ядер не должно иметь большого значения, не так ли? – ben

+0

@ben: Это правда. Тем не менее, слишком много потоков и открытых соединений одновременно могут быть контрпродуктивными. По-моему, Firefox использует по умолчанию 8 соединений для конвейерной обработки HTTP, поэтому теперь я использую это как предлагаемое значение (вместо 5). –

7

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

+1

Небезопасный поток – Imnl

Смежные вопросы