我有一个需要从远程服务器下载多个文件的PHP脚本。目前我只是循环下载并使用cURL处理文件,这意味着它不会开始下载一个文件,直到前一个文件完成 - 这会显着增加脚本运行时间。
是否可以启动多个cURL实例,例如,同时异步下载这些文件而无需等待前一个文件完成?如果是这样,这将如何实现?
答案 0 :(得分:21)
结帐curl-easy。它同时支持并行或单个请求的阻塞和非阻塞请求。此外,它是经过单元测试的,与许多简单或有缺陷的库不同。
披露:我是这个图书馆的作者。图书馆拥有自己的测试套件,所以我非常有信心它是健壮的。
另外,请查看以下使用示例:
<?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();
答案 1 :(得分:17)
是。
有multirequest PHP library(或参见:archived Google Code project)。它是一个多线程CURL库。
作为另一种解决方案,您可以编写一个脚本,以支持线程的语言(如Ruby或Python)执行此操作。然后,用PHP调用脚本。看起来很简单。
答案 2 :(得分:1)
@stil 的库是如此,很酷。非常感谢他!
尽管如此,我编写了一个很好的实用程序函数,可以很容易地从多个URL(在我的情况下是API)中获取异步内容并返回它们而不会丢失哪些信息。
您只需传递 key =&gt;即可运行它value 数组作为输入,它返回 key =&gt;响应数组结果: - )
/**
* 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 />
* e.g. 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 e.g.<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;
}
答案 3 :(得分:0)
对于PHP5.5 +, mpyw/co 是最终的解决方案。它的工作方式就像JavaScript中的tj/co一样。
假设您要下载指定的多个GitHub用户&#39;化身。每个用户都需要执行以下步骤。
<img class="avatar" src="...">
并请求(获取图片) ---
:等待我的回复
...
:在并行流程中等待其他响应
许多着名的基于curl_multi
的脚本已经为我们提供了以下流程。
/-----------GET HTML\ /--GET IMAGE.........\
/ \/ \
[Start] GET HTML..............----------------GET IMAGE [Finish]
\ /\ /
\-----GET HTML....../ \-----GET IMAGE....../
然而,这还不够有效。您想减少无用的等待时间...
吗?
/-----------GET HTML--GET IMAGE\
/ \
[Start] GET HTML----------------GET IMAGE [Finish]
\ /
\-----GET HTML-----GET IMAGE.../
是的,使用mpyw / co非常容易。有关更多详细信息,请访问存储库页面。
答案 4 :(得分:0)
在PHP 7.0&amp;如PHP exec Document中所述,Apache 2.0通过添加&#34;来重定向输出。的&安培;&GT; / dev / null&amp; &#34;在命令结束时,可以让它在后台运行,只需记住正确包装命令。
$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,但是在完成工作后,需要1500ms。
$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';
总的来说,添加&#34; &安培;&GT; / dev / null&amp;&#34;在命令结束时可能会有所帮助,只需记住正确地执行命令即可。