Khi tôi nghe ai đó sử dụng curl_multi_exec, thường thì họ chỉ tải nó với 100 url, sau đó đợi khi hoàn tất, sau đó xử lý tất cả, sau đó bắt đầu lại với 100 url tiếp theo ... Tôi đã làm như vậy, nhưng sau đó tôi phát hiện ra rằng có thể loại bỏ/thêm các chốt xử lý vào curl_multi trong khi vẫn còn một thứ gì đó, và nó thực sự tiết kiệm rất nhiều thời gian, đặc biệt nếu bạn sử dụng lại các kết nối đã mở. Tôi đã viết một thư viện nhỏ để xử lý hàng đợi các yêu cầu với các cuộc gọi lại; Tôi không đăng phiên bản đầy đủ ở đây tất nhiên ("nhỏ" vẫn là khá nhiều code), nhưng đây là một phiên bản đơn giản của điều chủ yếu để cung cấp cho bạn những ý tưởng chung:
public function launch() {
$channels = $freeChannels = array_fill(0, $this->maxConnections, NULL);
$activeJobs = array();
$running = 0;
do {
// pick jobs for free channels:
while (!(empty($freeChannels) || empty($this->jobQueue))) {
// take free channel, (re)init curl handle and let
// queued object set options
$chId = key($freeChannels);
if (empty($channels[$chId])) {
$channels[$chId] = curl_init();
}
$job = array_pop($this->jobQueue);
$job->init($channels[$chId]);
curl_multi_add_handle($this->master, $channels[$chId]);
$activeJobs[$chId] = $job;
unset($freeChannels[$chId]);
}
$pending = count($activeJobs);
// launch them:
if ($pending > 0) {
while(($mrc = curl_multi_exec($this->master, $running)) == CURLM_CALL_MULTI_PERFORM);
// poke it while it wants
curl_multi_select($this->master);
// wait for some activity, don't eat CPU
while ($running < $pending && ($info = curl_multi_info_read($this->master))) {
// some connection(s) finished, locate that job and run response handler:
$pending--;
$chId = array_search($info['handle'], $channels);
$content = curl_multi_getcontent($channels[$chId]);
curl_multi_remove_handle($this->master, $channels[$chId]);
$freeChannels[$chId] = NULL;
// free up this channel
if (!array_key_exists($chId, $activeJobs)) {
// impossible, but...
continue;
}
$activeJobs[$chId]->onComplete($content);
unset($activeJobs[$chId]);
}
}
} while (($running > 0 && $mrc == CURLM_OK) || !empty($this->jobQueue));
}
Trong phiên bản của tôi $ công việc thực sự là lớp riêng biệt, không phải là trường hợp của bộ điều khiển hoặc mô hình. Họ chỉ xử lý các tùy chọn thiết lập cURL, phân tích cú pháp phản hồi và gọi một cuộc gọi lại đã cho onComplete. Với cấu trúc này, các yêu cầu mới sẽ bắt đầu ngay sau khi một cái gì đó ra khỏi hồ bơi kết thúc.
Tất nhiên nó không thực sự giúp bạn tiết kiệm nếu không chỉ lấy mất thời gian nhưng chế biến là tốt ... Và nó không phải là một xử lý song song đúng sự thật. Nhưng tôi vẫn hy vọng nó sẽ giúp. :)
P.S. đã làm một thủ thuật cho tôi. :) Khi công việc 8 giờ hoàn thành trong 3-4 phút bằng cách sử dụng một nhóm gồm 50 kết nối. Không thể diễn tả cảm giác đó. :) Tôi đã không thực sự mong đợi nó hoạt động như kế hoạch, bởi vì với PHP nó hiếm khi hoạt động chính xác như ... Nó giống như "ok, hy vọng nó kết thúc trong ít nhất một giờ ... Wha ... Đợi .. 8-O "
PHP không thực sự được thiết kế để khởi chạy nhiều quy trình. Tại sao không nhìn vào một ngôn ngữ như python để thực hiện điều này? – afuzzyllama
@afuzzyllama Nó chỉ là một mô-đun phụ, toàn bộ dự án là trong PHP –
[nodejs] (http://nodejs.org) sẽ là hoàn hảo cho việc này. – Xeoncross