PHP异步编程:初学者完全指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

PHP异步编程简介

\n\n

传统的PHP是同步运行的:每个操作都按顺序执行。如果脚本需要发送HTTP请求或读取文件,它会等待操作完成,从而阻塞整个代码的执行。对于高负载的Web应用程序,这成为了瓶颈。异步编程解决了这个问题,它允许在不阻塞主线程的情况下同时执行多个任务。

\n\n

在本指南中,我们将探讨PHP中异步的工作原理、可用的工具以及如何在实际中使用它们。您将了解生成器、ReactPHP和Swoole库,以及PHP 8.1的新特性——Fiber。

\n\n

异步编程基础

\n\n

什么是异步,为什么需要它?

\n\n

想象一下您在准备早餐。同步方法:您烧上水,等待水烧开,然后开始煎蛋。异步方法:您烧上水,在水加热的同时,并行地煎蛋。在PHP中,这意味着您不必等待数据库或外部API的响应,而是可以执行其他代码。

\n\n

异步方法的主要优势:

\n
    \n
  • 提高I/O操作(网络、磁盘、数据库)的性能
  • \n
  • 节省服务器资源——更少的线程处理更多的请求
  • \n
  • 实现实时功能(聊天、通知、流媒体)的可能性
  • \n
\n\n

同步代码的问题

\n\n

考虑一个经典示例:从两个远程API获取数据。同步代码将按顺序执行:

\n\n
<?php\nfunction fetchData($url) {\n    $ch = curl_init($url);\n    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n    $result = curl_exec($ch); // 请求期间阻塞\n    curl_close($ch);\n    return $result;\n}\n\n$start = microtime(true);\n$data1 = fetchData('https://api.example.com/users');\n$data2 = fetchData('https://api.example.com/posts');\necho "时间: " . (microtime(true) - $start);\n?>
\n\n

如果每个请求需要2秒,总执行时间将是4秒,尽管我们可以并行执行请求。

\n\n

PHP中的异步工具

\n\n

1. 生成器 (yield) —— 轻量级异步

\n\n

生成器出现在PHP 5.5中,允许创建可以暂停执行并将控制权返回给调用代码的函数。这是创建协程的基础。

\n\n
<?php\nfunction generator() {\n    echo "生成器开始\\n";\n    yield 1;\n    echo "第一个yield之后\\n";\n    yield 2;\n    echo "结束\\n";\n}\n\n$gen = generator();\nforeach ($gen as $value) {\n    echo "收到: $value\\n";\n}\n?>
\n\n

生成器可以与事件循环结合使用来组织非阻塞操作。然而,要实现完整的异步功能,这还不够——需要一个库。

\n\n

2. ReactPHP —— 事件驱动库

\n\n

ReactPHP是一个流行的异步编程库。它提供了事件循环(Event Loop)、非阻塞套接字、HTTP客户端和服务器。通过Composer安装:

\n\n
composer require react/event-loop react/http
\n\n

异步HTTP请求示例:

\n\n
<?php\nrequire 'vendor/autoload.php';\n\nuse React\\EventLoop\\Factory;\nuse React\\HttpClient\\Client;\nuse React\\HttpClient\\Response;\n\n$loop = Factory::create();\n$client = new Client($loop);\n\n$request = $client->request('GET', 'https://api.example.com/data');\n$request->on('response', function (Response $response) {\n    $response->on('data', function ($chunk) {\n        echo "收到数据块: " . strlen($chunk) . " 字节\\n";\n    });\n    $response->on('end', function () {\n        echo "请求完成\\n";\n    });\n});\n$request->end();\n\necho "请求已发送,等待中...\\n";\n$loop->run();\n?                

博客

书籍推荐