是否可以使用PHP实现asynchronousHTTP请求?
我有一个PHP脚本,需要从远程服务器下载几个文件。 目前我只有一个循环下载和使用cURL处理文件,这意味着它不会开始下载一个文件,直到前一个文件完成 – 这大大增加了脚本运行时间。
是否可以启动多个cURL实例,例如,在不等待前一个完成的情况下,同时asynchronous下载这些文件? 如果是的话,这将如何完成?
是。
有多重请求的PHP库 (或者看: 存档的Google Code项目 )。 这是一个multithreading的CURL库。
作为另一种解决scheme,您可以编写一个脚本来支持线程,如Ruby或Python。 然后,用PHP调用脚本。 看起来很简单。
检查curl容易 。 它同时支持阻塞和不阻塞的请求,或同时支持单个请求。 此外,它是单位testing,不像许多简单或马车图书馆。
披露:我是这个图书馆的作者。 图书馆有它自己的testing套件,所以我非常有信心它是健壮的。
另外,请查看下面的使用示例:
<?php // We will download info about 2 YouTube videos: // http://youtu.be/XmSdTa9kaiQ and // http://youtu.be/6dC-sm5SWiU // Init queue of requests $queue = new cURL\RequestsQueue; // Set default options for all requests in queue $queue->getDefaultOptions() ->set(CURLOPT_TIMEOUT, 5) ->set(CURLOPT_RETURNTRANSFER, true); // Set callback function to be executed when request will be completed $queue->addListener('complete', function (cURL\Event $event) { $response = $event->response; $json = $response->getContent(); // Returns content of response $feed = json_decode($json, true); echo $feed['entry']['title']['$t'] . "\n"; }); $request = new cURL\Request('http://gdata.youtube.com/feeds/api/videos/XmSdTa9kaiQ?v=2&alt=json'); $queue->attach($request); $request = new cURL\Request('http://gdata.youtube.com/feeds/api/videos/6dC-sm5SWiU?v=2&alt=json'); $queue->attach($request); // Execute queue $queue->send();
@stil的图书馆非常酷。 非常感谢他!
不过,我写了一个很好的实用函数,可以很容易地从多个URL(我的例子中的API)获取asynchronous内容,并返回它们而不会丢失哪些信息。
你只要通过传递key => value数组作为input来运行它,并返回key =>响应数组作为结果: – )
/** * This function runs multiple GET requests parallely.<br /> * @param array $urlsArray needs to be in format:<br /> * <i>array(<br /> * [url_unique_id_1] => [url_for_request_1],<br /> * [url_unique_id_2] => [url_for_request_2],<br /> * [url_unique_id_3] => [url_for_request_3]<br /> * )</i><br /> * eg input like:<br /> * <i>array(<br /> * "myemail@gmail.com" => * "http://someapi.com/results?search=easylife",<br /> * "michael@gmail.com" => * "http://someapi.com/results?search=safelife"<br /> * )</i> * @return array An array where for every <i>url_unique_id</i> response to this request * is returned eg<br /> * <i>array(<br /> * "myemail@gmail.com" => <br /> * "Work less, enjoy more",<br /> * "michael@gmail.com" => <br /> * "Study, work, pay taxes"<br /> * )</i> * */ public function getResponsesFromUrlsAsynchronously(array $urlsArray, $timeout = 8) { $queue = new \cURL\RequestsQueue; // Set default options for all requests in queue $queue->getDefaultOptions() ->set(CURLOPT_TIMEOUT, $timeout) ->set(CURLOPT_RETURNTRANSFER, true); // ========================================================================= // Define some extra variables to be used in callback global $requestUidToUserUrlIdentifiers; $requestUidToUserUrlIdentifiers = array(); global $userIdentifiersToResponses; $userIdentifiersToResponses = array(); // ========================================================================= // Set function to be executed when request will be completed $queue->addListener('complete', function (\cURL\Event $event) { // Define user identifier for this url global $requestUidToUserUrlIdentifiers; $requestId = $event->request->getUID(); $userIdentifier = $requestUidToUserUrlIdentifiers[$requestId]; // ========================================================================= $response = $event->response; $json = $response->getContent(); // Returns content of response $apiResponseAsArray = json_decode($json, true); $apiResponseAsArray = $apiResponseAsArray['jobs']; // ========================================================================= // Store this response in proper structure global $userIdentifiersToResponses; $userIdentifiersToResponses[$userIdentifier] = $apiResponseAsArray; }); // ========================================================================= // Add all request to queue foreach ($urlsArray as $userUrlIdentifier => $url) { $request = new \cURL\Request($url); $requestUidToUserUrlIdentifiers[$request->getUID()] = $userUrlIdentifier; $queue->attach($request); } // ========================================================================= // Execute queue $queue->send(); // ========================================================================= return $userIdentifiersToResponses; }
对于PHP5.5 +, mpyw / co是最终的解决scheme。 它的工作方式就好像它是JavaScript中的tj / co 。
例
假设你想下载指定的多个GitHub用户的头像。 每个用户需要执行以下步骤。
- 获取http://github.com/mpyw(GET HTML)的内容
- find
<img class="avatar" src="...">
并请求它(GET IMAGE)
---
:等待我的回应
...
:在并行stream程中等待其他响应
许多着curl_multi
基于curl_multi
的脚本已经为我们提供了以下stream程。
/-----------GET HTML\ /--GET IMAGE.........\ / \/ \ [Start] GET HTML..............----------------GET IMAGE [Finish] \ /\ / \-----GET HTML....../ \-----GET IMAGE....../
但是,这不够有效。 你想减less毫无价值的等待时间...
?
/-----------GET HTML--GET IMAGE\ / \ [Start] GET HTML----------------GET IMAGE [Finish] \ / \-----GET HTML-----GET IMAGE.../
是的,这是很容易与mpyw / co。 有关更多详细信息,请访问存储库页面。
在PHP 7.0和Apache 2.0中,如PHP EXEC文档中所述,通过在命令末尾添加“ &gt; / dev / null& ”来redirect输出,可以使其在后台运行,只要记住正确地包装命令。
$time = microtime(true); $command = '/usr/bin/curl -H \'Content-Type: application/json\' -d \'' . $curlPost . '\' --url \'' . $wholeUrl . '\' >> /dev/shm/request.log 2> /dev/null &'; exec($command); echo (microtime(true) - $time) * 1000 . ' ms';
以上工作对我来说,只需要3ms,但以下将无法工作,需要1500毫秒。
$time = microtime(true); $command = '/usr/bin/curl -H \'Content-Type: application/json\' -d \'' . $curlPost . '\' --url ' . $wholeUrl; exec($command . ' >> /dev/shm/request.log 2> /dev/null &'); echo (microtime(true) - $time) * 1000 . ' ms';
总之,在命令的末尾添加“&> / dev / null&”可能会有所帮助,请记住正确地写入您的命令。