默认情况下,PHP 7是否可以异步处理请求?

时间:2019-02-28 15:35:42

标签: php asynchronous nonblocking

在过去的3.5年中,我一直在写PHP,我喜欢它。当最近的 PHP v / s Nodejs 嗡嗡声到来时,总是引起人们关注的一件事是 Nodejs 实现了非阻塞(或异步)I / O。默认情况下,PHP没有。

但是,当我最近尝试用PHP实现一个简单的异步请求路由器(使用 exec()函数)并尝试将我的代码与标准(可能是同步请求处理程序脚本)进行对比时,奇怪的东西。

在进一步解释之前,我希望您看一下下面的代码。

sync.php 应该搁置所有其他请求,直到当前请求完成处理为止的请求

<?php
    $a = $argv[1];
    echo "starting: ".$a;
    $ar = array();
    $sum = 0;
    $ul = 15000;
    for($i = 1; $i < $ul; $i++){
        $ar[$i] = $i;
    }
    for($i = 1; $i < $ul;  $i++){
        for($j = 1; $j < $ul; $j++){
            $sum += $ar[$j];
        }
    }
    echo "\n\nDone: ".$a."\nResult: ".$sum."\n";
?>

我做了两种测试。

首先,我在计算机上运行了该终端的四个实例并执行:

php sync.php 1  

同时全部

接下来,我打开XAMPP服务器,通过serveo公开我的本地主机,并同时从三个不同的设备向此脚本发出三个请求。

结果出乎意料。

无论我发送了多少个请求,它们(似乎都)并行执行,并且结果同时(考虑1-2秒的延迟)同时显示在所有终端窗口/浏览器选项卡上在每个终端窗口中手动运行命令时发生)。

这与PHP实现阻塞I / O的事实不符(这就是我发生的事情)。相反,我期望的是总爆破时间为

n * 4 seconds

其中n是处理每个请求所花费的时间(在我的笔记本电脑上大约为8秒)。

所以,为什么异步处理请求?是因为 for循环是异步执行的功能之一,还是与阻塞I / O模型完全没有关系?

2 个答案:

答案 0 :(得分:3)

您误解了有关阻止I / O的讨论。

每次从命令行运行PHP脚本时,它都会在一个完全独立的进程中执行,该进程不知道计算机上正在运行的任何其他PHP脚本。您可以多次执行它,其原因与您可以同时运行Web浏览器和文本编辑器的原因完全相同-操作系统正在调度一个或多个处理器内核上的进程。

在Web服务器示例中,它稍微复杂一点,但适用相同的原理:您对Web服务器的每个请求都将创建一个新进程或该进程内的新线程,并在其中运行PHP脚本。

人们正在讨论的有关阻止I / O的东西完全不同:当您访问外部内部的PHP代码时,例如使用HTTP请求获取Web内容。想象一下使用虚构的HTTP库的循环:

foreach ( $urls as $url ) {
    $results[] =  $httpClient->fetchUrl($url);
}

如果使用内置的PHP功能编写,则每次循环时将停止运行并等待远程服务器响应。因此,对于10个请求(每个请求花费一秒钟),将需要10秒来完成循环。

“非阻塞I / O”是指实现fetchUrl之类的功能,以便即使HTTP响应未返回,它们也立即返回。这样,您可以一次运行很多HTTP请求:在示例循环中,您将在1秒后获得所有10个响应。然后,您将有某种方式来获得结果,例如“承诺”。

可以在PHP中实现此功能,但默认情况下并没有以用户友好的方式执行此功能的本地函数。

更复杂的是,系统可以为 input 实现此功能:每当您在等待外部事件时,都可以检查是否有新的Web请求进入并开始处理。这样可以有效地模拟多个线程,这是NodeJS通过每个请求使用一个线程处理大量流量的方式。

答案 1 :(得分:2)

单个PHP 进程被阻止。例如,您可以使用built-in development server,这将启动单进程Web服务器。根据其中的注释:

  

Web服务器仅运行一个单线程进程,因此如果请求被阻止,PHP应用程序将停止。

由于显而易见的原因,如果您有成千上万的人同时访问您的网站,这是有问题的,所以有一个简单的解决方案-多个PHP进程。可以通过多种方式进行设置-Apache将fire up multiple webserver workers,或者您可以运行PHP-FPM ("FastCGI Process Manager")。

只要他们是自由工作者,他们将并行处理传入的请求。