是否可以使用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 /> * &nbsp; "myemail@gmail.com" => * &nbsp; "http://someapi.com/results?search=easylife",<br /> * &nbsp; "michael@gmail.com" => * &nbsp; "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 /> * &nbsp; "myemail@gmail.com" => <br /> * &nbsp; "Work less, enjoy more",<br /> * &nbsp; "michael@gmail.com" => <br /> * &nbsp; "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用户的头像。 每个用户需要执行以下步骤。

  1. 获取http://github.com/mpyw(GET HTML)的内容
  2. 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&”可能会有所帮助,请记住正确地写入您的命令。