PHP中是否有一种方法可以使HTTP调用不等待响应?我不关心响应,我只想做一些类似file_get_contents()的事情,但不等待请求完成后再执行其余的代码。这对于在我的应用程序中触发某种“事件”或触发长进程非常有用。
什么好主意吗?
PHP中是否有一种方法可以使HTTP调用不等待响应?我不关心响应,我只想做一些类似file_get_contents()的事情,但不等待请求完成后再执行其余的代码。这对于在我的应用程序中触发某种“事件”或触发长进程非常有用。
什么好主意吗?
当前回答
/**
* Asynchronously execute/include a PHP file. Does not record the output of the file anywhere.
*
* @param string $filename file to execute, relative to calling script
* @param string $options (optional) arguments to pass to file via the command line
*/
function asyncInclude($filename, $options = '') {
exec("/path/to/php -f {$filename} {$options} >> /dev/null &");
}
其他回答
你可以在PHP中使用非阻塞套接字和pecl扩展之一:
http://php.net/event http://php.net/libevent http://php.net/ev https://github.com/m4rw3r/php-libev
您可以使用库,它为您的代码和pecl扩展之间提供了一个抽象层:https://github.com/reactphp/event-loop
您还可以使用基于前面库的异步http-client: https://github.com/reactphp/http-client
查看ReactPHP的其他库:http://reactphp.org
使用异步模型时要小心。 我推荐在youtube上看这个视频:http://www.youtube.com/watch?v=MWNcItWuKpI
我发现这个软件包非常有用,非常简单:https://github.com/amphp/parallel-functions
<?php
use function Amp\ParallelFunctions\parallelMap;
use function Amp\Promise\wait;
$responses = wait(parallelMap([
'https://google.com/',
'https://github.com/',
'https://stackoverflow.com/',
], function ($url) {
return file_get_contents($url);
}));
它将并行加载所有3个url。 您还可以在闭包中使用类实例方法。
例如,我使用Laravel扩展基于这个包https://github.com/spatie/laravel-collection-macros#parallelmap
这是我的代码:
/**
* Get domains with all needed data
*/
protected function getDomainsWithdata(): Collection
{
return $this->opensrs->getDomains()->parallelMap(function ($domain) {
$contact = $this->opensrs->getDomainContact($domain);
$contact['domain'] = $domain;
return $contact;
}, 10);
}
它在10个并行线程中加载所有需要的数据,而不是在没有异步的情况下50秒,它在8秒内完成。
下面是一个工作示例,只需运行它,然后打开storage.txt,检查神奇的结果
<?php
function curlGet($target){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec ($ch);
curl_close ($ch);
return $result;
}
// Its the next 3 lines that do the magic
ignore_user_abort(true);
header("Connection: close"); header("Content-Length: 0");
echo str_repeat("s", 100000); flush();
$i = $_GET['i'];
if(!is_numeric($i)) $i = 1;
if($i > 4) exit;
if($i == 1) file_put_contents('storage.txt', '');
file_put_contents('storage.txt', file_get_contents('storage.txt') . time() . "\n");
sleep(5);
curlGet($_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?i=' . ($i + 1));
curlGet($_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?i=' . ($i + 1));
您可以使用exec()来调用一些可以执行HTTP请求的东西,如wget,但必须将程序的所有输出指向某个地方,如文件或/dev/null,否则PHP进程将等待该输出。
如果你想把进程和apache线程完全分开,可以尝试这样做(我不确定,但我希望你能明白):
exec('bash -c "wget -O (url goes here) > /dev/null 2>&1 &"');
这不是一项很好的业务,您可能需要类似cron作业的东西来调用heartbeat脚本,该脚本轮询实际的数据库事件队列来执行真正的异步事件。
ReactPHP异步http客户端 https://github.com/shuchkin/react-http-client
通过Composer安装
$ composer require shuchkin/react-http-client
异步HTTP GET
// get.php
$loop = \React\EventLoop\Factory::create();
$http = new \Shuchkin\ReactHTTP\Client( $loop );
$http->get( 'https://tools.ietf.org/rfc/rfc2068.txt' )->then(
function( $content ) {
echo $content;
},
function ( \Exception $ex ) {
echo 'HTTP error '.$ex->getCode().' '.$ex->getMessage();
}
);
$loop->run();
在cli模式下运行php
$ php get.php