2012-01-08 13 views
7

Mam tablicę adresów URL i nie chcę otwierać każdego z nich i pobrać określonego tagu.
Ale chcę to zrobić równolegle.Równoległe żądania HTTP w ruby ​​

Oto pseudokod za to, co chcę zrobić:

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

jeżeli mogłoby to być zrobione w miły i bezpieczny sposób, że byłoby super.
Mogę użyć wątku, ale nie wygląda na to, że tablice są bezpieczne dla wątków w ruby.

Odpowiedz

25

Można osiągnąć wątku bezpieczeństwa za pomocą 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) 

To może być jednak przeciwny skutek do korzystania z nowego wątku dla każdego adresu URL, więc ograniczenie liczby wątków jak to może być bardziej wydajnych :

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

Haha, to było dokładnie to samo rozwiązanie, które napisałem! :) –

+0

Jeśli większość pracy to IO, liczba rdzeni nie powinna mieć znaczenia, czy nie? – ben

+0

@ben: To prawda. Nadal jednak posiadanie zbyt wielu wątków i otwartych połączeń w tym samym czasie może przynosić efekty odwrotne do zamierzonych. Firefox używa domyślnie 8 połączeń do potokowania HTTP, tak myślę, więc używam tego jako sugerowanej wartości (zamiast 5). –

7

Zestaw klejnotów został zaprojektowany, aby zrobić to z łatwością. Jest to bardzo wygodne i potężne.

+1

Nie wątek bezpieczny – Imnl

Powiązane problemy