PHP中发起并发请求
1.curl_multi_*
<?php
$stime = microtime(true);
// build the individual requests, but do not execute them
$ch_1 = curl_init('http://example.com/time?sleep=1');
$ch_2 = curl_init('http://example.com/time?sleep=2');
curl_setopt($ch_1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch_2, CURLOPT_RETURNTRANSFER, true);
// build the multi-curl handle, adding both $ch
$mh = curl_multi_init();
curl_multi_add_handle($mh, $ch_1);
curl_multi_add_handle($mh, $ch_2);
// execute all queries simultaneously, and continue when all are complete
$running = null;
do {
curl_multi_exec($mh, $running);
} while ($running);
//close the handles
curl_multi_remove_handle($mh, $ch_1);
curl_multi_remove_handle($mh, $ch_2);
curl_multi_close($mh);
// all of our requests are done, we can now access the results
$response_1 = curl_multi_getcontent($ch_1);
$response_2 = curl_multi_getcontent($ch_2);
//echo "$response_1 $response_2"; // output results
$etime = microtime(true);
echo $etime - $stime;
- 缺点:得等所有的请求都结束之后才能操作数据
- 代码比较底层,需要封装下好使
- 最好给每个请求设置超时时间,防止阻塞
2.guzzle
- 也是使用的curl_multi_*
- 使用guzzlehttp/promises 包装了一下,更好使了。
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Promise\Utils;
$stime = microtime(true);
$client = new Client();
$promises = [
'1' => $client->getAsync('http://example.com/time?sleep=1'),
'2' => $client->getAsync('http://example.com/time?sleep=3'),
];
// Wait on all of the requests to complete.
$results = Utils::unwrap($promises);
$etime = microtime(true);
// You can access each result using the key provided to the unwrap
// function.
dump((string)$results['1']->getBody());
dump((string)$results['2']->getBody());
echo $etime - $stime;
3.队列worker(多进程)
这个就是直接先把待请求的地址,统统扔到队列里面去,让worker来执行
- 可以及时的处理单个请求返回
- 并发量取决于worker数量
- 如果想要所有请求结束后处理一些事情,需要手动管理请求计数器
4.手动多进程
<?php
$s = microtime(true);
$worker_num = 2;
$i = 0;
$pids = [];
do {
$i++;
$pid = pcntl_fork();
if ($pid === -1) {
die("can't fork !");
} elseif ($pid !== 0) // main
{
$pids[$pid] = $pid;
} else // child
{
file_get_contents('http://example.com/time?sleep=' . $i);
exit(0);
}
} while ($i < $worker_num);
do // main
{
$pid = pcntl_wait($status);
unset($pids[$pid]);
} while (count($pids));
$e = microtime(true);
var_dump($e - $s);
- 比上面的从操作系统层面起多进程复杂一些,需要手动管理进程
- 跨进程了,主进程需要通过redis等获取子进程数据
5.swoole,协程
<?php
$s = microtime(true);
Co\run(function () {
go(function (){
file_get_contents('http://example.com/time?sleep=1');
});
go(function (){
file_get_contents('http://example.com/time?sleep=2');
});
});
$e = microtime(true);
var_dump($e - $s);
<?php
use function Swoole\Coroutine\run;
use Swoole\Runtime;
use Swoole\Coroutine\WaitGroup;
Runtime::enableCoroutine();
run(function () {
$s = microtime(true);
$wg = new WaitGroup();
$result = [];
$wg->add();
go(function () use ($wg, &$result) {
$result['x'] = file_get_contents('http://example.com/time?sleep=1');
$wg->done();
});
$wg->add();
go(function () use ($wg, &$result) {
$result['y'] = file_get_contents('http://example.com/time?sleep=2');
$wg->done();
});
//挂起当前协程,等待所有任务完成后恢复
$wg->wait();
$e = microtime(true);
var_dump($e - $s);
var_dump($result);
});
- 代码简洁
- 可以使用WaitGroup等待数据完成后处理后续逻辑
6.fiber >8.1
赞助一杯咖啡☕️
本文由 widdy 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jan 18, 2022 at 10:41 am