2010-01-24 45 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

Mã này hoạt động theo kiểu đồng bộ. Yêu cầu đầu tiên, thứ hai, thứ ba. Tôi muốn gửi tất cả các yêu cầu không đồng bộ và in urls sau khi tất cả các yêu cầu được thực hiện.Thực hiện nhiều yêu cầu HTTP không đồng bộ

Cách tốt nhất để làm điều đó là gì? Fiber có phù hợp với điều đó không?

Trả lời

1

Điều này có thể được thực hiện với thư viện C cURL. Một ruby binding cho thư viện đó tồn tại, nhưng nó dường như không hỗ trợ chức năng này ra khỏi hộp. Tuy nhiên, có vẻ như có a patch thêm/sửa chữa nó (ví dụ mã có sẵn trên trang). Tôi biết điều này nghe không hay, nhưng có thể đáng thử nếu không có đề xuất nào tốt hơn.

0

Bạn có thể có một chủ đề khác nhau thực hiện mỗi một trong những Net :: HTTP.get. Và chỉ cần đợi cho tất cả các chủ đề kết thúc.

Các url in BTW sẽ in cả liên kết và nội dung.

12

Dưới đây là ví dụ sử dụng chuỗi.

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

Có vẻ như nó hoạt động. Nhưng làm thế nào để giết thread nếu máy chủ không đáp ứng sau 15 giây? – NVI

+1

Bạn có thể sử dụng 'Timeout.timeotu (20) do .... end'. Tuy nhiên, điều đó làm tăng một lỗi, vì vậy bạn sẽ cần phải làm điều gì đó với luồng chương trình của bạn và có cách gắn thẻ rằng yêu cầu đã được hoàn thành ngoài việc kiểm tra xem khóa 'nội dung' tồn tại chưa. –

+0

Là mạng của Ruby :: HTTP an toàn? – Daniel777

11

Tôi chỉ thấy này, một năm và một chút sau, nhưng hy vọng không quá muộn đối với một số googler ...

Typhoeus đến nay là giải pháp tốt nhất cho việc này. Nó kết thúc tốt đẹp libcurl trong một thời trang thực sự thanh lịch. Bạn có thể đặt max_concurrency lên tới khoảng 200 mà không bị nghẹt thở.

Đối với timeout, nếu bạn vượt qua Typhoeus một lá cờ :timeout, nó sẽ chỉ đăng ký thời gian chờ là phản hồi ... và sau đó bạn thậm chí có thể đặt lại yêu cầu trong một hydra khác để thử lại nếu bạn muốn.

Đây là chương trình của bạn được viết lại bằng Typhoeus. Hy vọng rằng điều này sẽ giúp bất cứ ai đi qua trang này sau!

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

Các work_queue đá quý là cách dễ nhất để thực hiện nhiệm vụ không đồng bộ và đồng thời trong ứng dụng của bạn.

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

Tôi đã viết một bài đăng blog chuyên sâu về chủ đề này trong đó bao gồm một câu trả lời đó là hơi tương tự như tháng tám đăng - nhưng với một vài khác biệt quan trọng: 1) Theo dõi mọi thông tài liệu tham khảo chủ đề trong mảng "thread". 2) Sử dụng phương pháp "nối" để kết nối các chủ đề ở cuối chương trình.

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!" 

Các hướng dẫn đầy đủ (và một số thông tin hiệu suất) có sẵn ở đây: https://zachalam.com/performing-multiple-http-requests-asynchronously-in-ruby/

Các vấn đề liên quan