<?php
$urls = array(
'task1' => "http://localhost/sleep1.php", // sleep(1) 后返回
'task2' => "http://localhost/sleep2.php", // sleep(2) 后返回
);
$mh = curl_multi_init();
foreach ($urls as $key => $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_multi_add_handle($mh, $ch);
// 资源id,用以标识请求
$id = (int)$ch;
// 回调函数
$task[$id]['callback'] = function($content)use($key) {
echo $content;
// 请求返回后创建文件,并记录时间
file_put_contents($key, time());
};
}
do{
// 执行
$status = curl_multi_exec($mh, $active);
// 避免cpu使用率过高
if ($active && curl_multi_select($mh) === -1)
usleep(250);
// 等待请求返回
while($done = curl_multi_info_read($mh)) {
$id = (int)$done['handle'];
// 读取返回
$content = curl_multi_getcontent($done['handle']);
// 执行回调函数
$task[$id]['callback']($content);
}
}while ($status === CURLM_CALL_MULTI_PERFORM || $active);
文件task2的创建时间比task1迟1秒,说明两个请求是并发的。
如果使用curl单线程循环发送请求,必须等待task1请求完毕,执行完回调后,再发送task2请求。
由于curl_multi是多线程的,两个请求同时发送,task1先返回后会马上执行回调函数,同时等待task2返回。如果有多个采集任务,这样可以节省很多时间。
但即使这样也只能实现“准多线程”。
// 将回调函数修改
function($content)use($key) {
echo $content;
// 请求返回后创建文件,并记录时间
file_put_contents($key, time());
// 加上这句
if($key == 'task1')
sleep(3);
};
task2文件创建时间比task1迟3秒,说明task1的回调函数阻塞了task2回调的执行。
curl_multi在其内部实现了多线程发送请求,但在php代码层面仍然是单线程阻塞的。