2010-01-24 5 views
8
require 'net/http' 

urls = [ 
    {'link' => 'http://www.google.com/'}, 
    {'link' => 'http://www.yandex.ru/'}, 
    {'link' => 'http://www.baidu.com/'} 
] 

urls.each do |u| 
    u['content'] = Net::HTTP.get(URI.parse(u['link'])) 
end 

print urls

Bu kod, eşzamanlı olarak çalışır. İlk istek, ikinci, üçüncü. Tüm istekleri eşzamansız olarak göndermek ve hepsi tamamlandıktan sonra urls'u yazdırmak istiyorum.Eşzamansız olarak birden çok HTTP isteği oluşturma

Bunu yapmanın en iyi yolu nedir? Elyaf bunun için uygun mu?

cevap

1

Bu, C kütüphanesi cURL ile yapılabilir. Bu kitaplık için ruby binding var, ancak bu işlevsellik kutusunun dışında desteklenmiyor gibi görünüyor. Ancak, a patch eklenmesi/sabitlenmesi gibi görünüyor (örnek kod sayfada mevcuttur). Bunun iyi gelmediğini biliyorum, ancak daha iyi bir öneri yoksa denemeye değer olabilir.

0

Farklı iplik Net :: HTTP.get her biri yürütmek olabilir. Ve tüm iş parçacığının bitmesini bekleyin.

BTW yazdırma URL'leri hem bağlantıyı hem de içeriği yazdıracaktır.

12

İşte konuları kullanarak bir örnek.

require 'net/http' 

urls = [ 
    {'link' => 'http://www.google.com/'}, 
    {'link' => 'http://www.yandex.ru/'}, 
    {'link' => 'http://www.baidu.com/'} 
] 

urls.each do |u| 
    Thread.new do 
    u['content'] = Net::HTTP.get(URI.parse(u['link'])) 
    puts "Successfully requested #{u['link']}" 

    if urls.all? {|u| u.has_key?("content") } 
     puts "Fetched all urls!" 
     exit 
    end 
    end 
end 

sleep 
+0

görünüyor. Ama sunucu 15 saniye sonra yanıt vermiyorsa iş parçacığı nasıl öldürülür? – NVI

+1

'Timeout.timeotu (20) do .... end' kullanabilirsiniz. Bu da bir hata yaratır, bu nedenle program akışınız ile bir şeyler yapmanız ve bir içeriğin "içerik" anahtarının mevcut olup olmadığını kontrol etmekten başka bir şeyin tamamlandığını etiketlemenin bir yoluna sahip olmanız gerekir. –

+0

Ruby's Net :: HTTP threadsafe nedir? – Daniel777

11

Ben sadece bir yıl ve biraz sonra bu gördük, ama bunun için umarım çok geç değil bazı Google çalışanı için ...

Typhoeus arayla en iyi çözüm. Libcurl'u gerçekten zarif bir şekilde sarar. max_concurrency'u boğulmadan yaklaşık 200'e ayarlayabilirsiniz.

Zamanaşımlarıyla ilgili olarak, Typhoeus a :timeout bayrağını geçirirseniz, yanıt olarak bir zaman aşımı kaydeder ... ve daha sonra isterseniz tekrar denemek için isteği tekrar başka bir hidraya koyabilirsiniz.

İşte programınız Typhoeus ile yeniden yazılmıştır. Umarım bu, daha sonra bu sayfaya giren herkese yardımcı olur!

require 'typhoeus' 

urls = [ 
    'http://www.google.com/', 
    'http://www.yandex.ru/', 
    'http://www.baidu.com/' 
] 

hydra = Typhoeus::Hydra.new 

successes = 0 

urls.each do |url| 
    request = Typhoeus::Request.new(url, timeout: 15000) 
    request.on_complete do |response| 
     if response.success? 
      puts "Successfully requested " + url 
      successes += 1 
     else 
      puts "Failed to get " + url 
     end 
    end 
    hydra.queue(request) 
end 

hydra.run 

puts "Fetched all urls!" if successes == urls.length 
0

work_queue mücevher uygulamanızda uyumsuz ve eşzamanlı görevleri gerçekleştirmek için en kolay yoludur. 1) tüm iplik referansların kaydını tutar: ancak birkaç temel fark vardır -

wq = WorkQueue.new 2 # Limit the maximum number of simultaneous worker threads 

urls.each do |url| 
    wq.enqueue_b do 
    response = Net::HTTP.get_response(url) 
    # use the response 
    end 
end 

wq.join # All requests are complete after this 
1

Ben yayınlanmıştır biri Ağustos biraz benzer bir cevap içeren bu konu hakkında derinlemesine bir blog yazısı yazdım "thread" dizisi. 2) Programın sonunda konuları bağlamak için "birleştir" yöntemini kullanır.

require 'net/http' 

# create an array of sites we wish to visit concurrently. 
urls = ['link1','link2','link3'] 
# Create an array to keep track of threads. 
threads = [] 

urls.each do |u| 
    # spawn a new thread for each url 
    threads << Thread.new do 
    Net::HTTP.get(URI.parse(u)) 
    # DO SOMETHING WITH URL CONTENTS HERE 
    # ... 
    puts "Request Complete: #{u}\n" 
    end 
end 

# wait for threads to finish before ending program. 
threads.each { |t| t.join } 

puts "All Done!" 

tam öğretici (ve bazı performans bilgisi) buradan ulaşılabilir: Çalışır gibi https://zachalam.com/performing-multiple-http-requests-asynchronously-in-ruby/