前言:
当前各位老铁们对“curlphp”大概比较关切,大家都需要分析一些“curlphp”的相关资讯。那么小编在网上搜集了一些关于“curlphp””的相关内容,希望看官们能喜欢,咱们一起来了解一下吧!我认为没有使用线程的任何好的用例 在 PHP 中,但 还有一些工具(swoole、workerman以及衍生的工具)不容忽视!可以在 PHP 中异步执行(至少一件事)——开箱即用!
考虑这样一个例子:
你想向外部(一个或 4 个不同的)服务发出 4 个请求——所有 4 个请求的“时间成本”是多少?
有两种可能情况:
我们可以同步处理请求——那么总时间就是所有后续请求成本的总和我们可以异步完成它们——总时间将等于最长请求的时间
请参见下图以可视化场景,假设我们必须发出 4 个请求,其中:
第一个的响应是立即的(我们可以忽略延迟)第二个响应在 1 秒后出现第三次的回应——2秒第四次的回应——3秒
什么适用于 PHP?
让我们检查一下(您可以在下面找到所执行测试的解释,结果用了3s多):
docker compose run phpSequence: 0 .. 3...endWoke up after 0 second(s) of sleep!Woke up after 1 second(s) of sleep!Woke up after 2 second(s) of sleep!Woke up after 3 second(s) of sleep!real 0m3.099s这里究竟测试了什么?
作为“外部服务”,我使用了我称之为“睡眠服务器”的工具——你可以向该工具(服务)发送一个请求,并将秒数作为参数,它会在请求的时间后做出响应(更多信息和示例 可以在项目的自述文件中找到)。
测试PHP代码:
$client = new GuzzleHttp\Client();for($i = $sequenceStart; $i <= $sequenceStop; $i++) { Utils::task( fn() => $client->getAsync("{$sleepingUrl}/{$i}") ->then($printResponse) ->wait() );}echo 'end' . PHP_EOL;
所有这些都被 docker-compose 绑定了:
services: sleeping: build: "; php: build: ./php environment: SLEEPING_URL: "; depends_on: - sleeping ...
代码示例:
让我们将 PHP(php:8.1 )结果与 JS 代码进行比较。
代码的JS版本:
for (let i=sequenceStart; i<=sequenceStop; i++) { fetch(`${sleepingUrl}/${i}`) .then(response => response.text()) .then(result => console.log(result))}console.log('end')
测试
docker compose run jsSequence: 0 .. 3 ...endWoke up after 0 second(s) of sleep!Woke up after 1 second(s) of sleep!Woke up after 2 second(s) of sleep!Woke up after 3 second(s) of sleep!real 0m3.182s
结果几乎相同!
事情要解释
我认为有两个(关于 PHP 代码):
为什么要执行这些请求? (请注意脚本输出中打印的“end”字符串——它是脚本的最后一行!)
为什么这些请求是异步执行的?
第一个有点奇怪——我的意思是——答案(至少对我而言)。 让我解释:
我们从 Util::task() 开始,因为它已在我的示例中使用 - 检查该方法(它在 GuzzleHttp\Promise 命名空间中声明)! 你可以在那里找到类似 $queue = self::queue()
按照此跟踪并检查 queue() 方法。 如果队列不存在,则会创建它: $queue = new TaskQueue() (在我们的例子中会发生什么)——让我们打开 TaskQueue 构造函数:
public function __construct($withShutdown = true){ if ($withShutdown) { register_shutdown_function(function () { if ($this->enableShutdown) { // Only run the tasks if an E_ERROR didn't occur. $err = error_get_last(); if (!$err || ($err['type'] ^ E_ERROR)) { $this->run(); } } }); }}
register_shutdown_function!起初它让我感到惊讶,如果 PHP 中有这样的可能性,为什么不使用它们(但是,我对此不确定)。
现在:
为什么这些请求是异步执行的?
因为 curl 库允许这样做!
-Z, —平行
与常规串行方式相比,使 curl 并行执行其传输。
PHP 也使用这个库——php 解释器可以用它编译,也可以作为扩展添加——PHP 扩展可以通过 php -m 检查:
php -m...curl...
Curl PHP 扩展提供了对系统 curl 库的访问——你可以使用 cli curl 接口(如果我检查正确的话):
docker run --rm -ti php:8.1 bash...# ldd /usr/local/bin/php | grep curl libcurl.so.4 => /usr/lib/x86_64-linux-gnu/libcurl.so.4 ...# ldd /usr/bin/curl | grep libcurl libcurl.so.4 => /usr/lib/x86_64-linux-gnu/libcurl.so.4 ...
它是一个用 C编写的工具,可以利用线程并且 PHP API 提供了一种利用 libcurl 库提供的多线程功能的方法!
接下来是下一部分——如果您想直接使用此功能,我的意思是按照 PHP API 描述它的方式,那么讨论的代码可能如下所示:
<?phprequire_once __DIR__ . '/../vendor/autoload.php';$sleepingUrl = getenv('SLEEPING_URL') ?: ";;$multi = curl_multi_init();$stillRunning = null;for ($i = 0; $i <= 3; $i++) { $curl = curl_init("{$sleepingUrl}/{$i}"); curl_multi_add_handle($multi, $curl);}do { $status = curl_multi_exec($multi, $stillRunning); if ($stillRunning) { curl_multi_select($multi); }} while ($stillRunning && $status == CURLM_OK);
上面的脚本可以在这里找到并由(对不起那个小cli-monster)执行/测试:
docker compose run \ --entrypoint "/bin/bash -c \"time php bin/fetch_mcurl.php\"" php
你可以像那样使用它——但它看起来不会比上面提供的解决方案复杂得多:
Utils::task( fn() => $client->getAsync("{$sleepingUrl}/{$i}") ->then($printResponse) ->wait());
对于我来说,通过 Guzzle 开发人员实现的 promise 接口的使用看起来好多了
标签: #curlphp