2012-06-23 20 views
5

Tôi đang thực hiện rất nhiều yêu cầu HTTP và tôi đã chọn HTTP :: Async để thực hiện công việc. Tôi đã thực hiện hơn 1000 yêu cầu và nếu tôi chỉ làm như sau (xem mã bên dưới), rất nhiều yêu cầu hết thời gian chờ xử lý vì có thể mất hàng chục phút trước khi xử lý cho họ:Làm cách nào để thực hiện 25 yêu cầu cùng một lúc với HTTP :: Async trong Perl?

for my $url (@urls) { 
    $async->add(HTTP::Request->new(GET => $url)); 
} 
while (my $resp = $async->wait_for_next_response) { 
    # use $resp 
} 

Vì vậy, tôi quyết định thực hiện 25 yêu cầu mỗi lần, nhưng tôi không thể nghĩ ra cách để thể hiện nó bằng mã.

tôi thử như sau:

while (1) { 
    L25: 
    for (1..25) { 
     my $url = shift @urls; 
     if (!defined($url)) { 
      last L25; 
     } 
     $async->add(HTTP::Request->new(GET => $url)); 
    } 
    while (my $resp = $async->wait_for_next_response) { 
     # use $resp 
    } 
} 

Tuy nhiên điều này không làm việc cũng như bởi vì nó quá chậm bây giờ. Bây giờ nó chờ đợi cho đến khi tất cả 25 yêu cầu đã được xử lý cho đến khi nó thêm một 25. Vì vậy, nếu nó có 2 yêu cầu trái, nó không có gì. Tôi đã chờ tất cả các yêu cầu được xử lý để thêm lô tiếp theo 25.

Làm cách nào để cải thiện logic này để làm cho một số việc trong khi xử lý hồ sơ, nhưng cũng đảm bảo chúng không hết thời gian chờ.

Trả lời

1

Bạn thân thiết, bạn chỉ cần kết hợp hai cách tiếp cận! :-)

Chưa được kiểm tra, do đó, hãy nghĩ đó là mã giả. Đặc biệt tôi không chắc chắn nếu total_count là phương pháp phù hợp để sử dụng, tài liệu không nói. Bạn cũng có thể chỉ có một số truy cập $active_requests mà bạn ++ khi thêm yêu cầu và -- khi bạn nhận được phản hồi.

while (1) { 

    # if there aren't already 25 requests "active", then add more 
    while (@urls and $async->total_count < 25) { 
     my $url = shift @urls; 
     $async->add(...); 
    } 

    # deal with any finished requests right away, we wait for a 
    # second just so we don't spin in the main loop too fast. 
    while (my $response = $async->wait_for_next_response(1)) { 
     # use $response 
    } 

    # finish the main loop when there's no more work 
    last unless ($async->total_count or @urls); 

} 
2

Nếu bạn không thể gọi wait_for_next_response đủ nhanh vì bạn đang thực hiện mã khác, giải pháp đơn giản nhất là làm cho mã bị gián đoạn bằng cách di chuyển mã đến một chuỗi thực thi riêng biệt. Nhưng nếu bạn sẽ bắt đầu sử dụng các chủ đề, tại sao sử dụng HTTP :: Async?

use threads; 
use Thread::Queue::Any 1.03; 

use constant NUM_WORKERS => 25; 

my $req_q = Thread::Queue::Any->new(); 
my $res_q = Thread::Queue::Any->new(); 

my @workers; 
for (1..NUM_WORKERS) { 
    push @workers, async { 
     my $ua = LWP::UserAgent->new(); 
     while (my $req = $req_q->dequeue()) { 
     $res_q->enqueue($ua->request($req)); 
     } 
    };  
} 

for my $url (@urls) { 
    $req_q->enqueue(HTTP::Request->new(GET => $url)); 
} 

$req_q->enqueue(undef) for @workers; 

for ([email protected]) { 
    my $res = $res_q->dequeue(); 
    ... 
} 

$_->join() for @workers; 
+0

Xin chào ikegami, tôi cố gắng chạy mã mẫu nhưng tiếc là tôi nhận được thông báo sau: 400 Không thể xác định phương pháp đối tượng "lược đồ" qua gói "URI :: http - đây là vấn đề sheme URI nhưng tôi sử dụng đúng URI "http://www.web.de". bạn có thể tìm thấy mã nguồn của tôi trong http://www.sourcepod.com/pqyyxw07-51950.thx – ovntatar

+0

xin lỗi, stackoverflow định dạng liên kết của tôi. liên kết là: http: // www. web. de -> xóa không gian char – ovntatar

+0

nhưng tuy nhiên tôi có thể sử dụng bất kỳ URL nào khác và tôi nhận được lỗi tương tự, ví dụ: http: // google. com – ovntatar

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