PHP8.1新特性大讲解之Fibers with a grain of salt

PHP8.1新特性大讲解之Fibers with a grain of salt,第1张

PHP8.1新特性大讲解之Fibers with a grain of salt

本文系翻译,原文地址:https://stitcher.io/blog/fibers-with-a-grain-of-salt

Fibers with a grain of salt

所以我打算写一篇关于在PHP 8.1 中使用Fibers纤维的深入博客文章。我们将从一个基本示例开始,从头开始解释它们。这个想法是发送异步 HTTP 请求并使用纤程并行处理它们。

但是和他们一起玩,我了解到RFC并不是在开玩笑,当它说“不应直接在应用程序级代码中使用 Fiber API。Fibers 提供了一个基本的、低级的流控制 API 来创建更高然后在应用程序代码中使用的级抽象”。

因此,与其走这条路并使事情变得过于复杂,我们将讨论什么是纤程概念,为什么它们在应用程序代码中几乎不可用,以及您到底如何使用异步 PHP。

首先,一点点理论。

假设您要发送三个 HTTP 请求并处理它们的组合结果。这样做的同步方式是发送第一个,等待响应,然后发送第二个,等待,等等。

让我们用尽可能简单的图表来表示这样的程序流程。你需要从上到下阅读这张图表,时间越往下越走。每种颜色代表一个 HTTP 请求。每个请求的彩色部分代表实际运行的 PHP 代码,您服务器上的 CPU 正在执行工作,透明块代表等待时间:请求需要通过网络发送,其他服务器需要处理并发送回. 只有当响应到达时,我们才能再次工作。

这是一个同步执行流程:发送、等待、处理、重复。

在并行处理的世界中,我们发送请求但不等待。然后我们发送下一个请求,然后是另一个。只有然后我们等待所有请求。在等待的同时,我们会定期检查我们的一个请求是否已经完成。如果是这种情况,我们可以立即处理。

您可以看到这种方法如何减少执行时间,因为我们更优化地使用了等待时间。

Fibers 是 PHP 8.1 中的一种新机制,可让您更有效地管理这些并行执行路径。使用生成器和 已经可以实现yield,但是纤维是一个显着的改进,因为它们是专门为此用例设计的。

您将为每个请求创建一个纤程,并在请求发送后暂停纤程。创建所有三个光纤后,您将遍历它们,并一一恢复它们。通过这样做,纤程检查请求是否已经完成,如果没有则再次暂停,否则它可以处理响应并最终完成。

你看,纤程是一种启动、暂停和恢复程序隔离部分执行流程的机制。Fiber 也被称为“绿色线程”:实际上存在于同一进程中的线程。这些线程不是由 *** 作系统管理的,而是由运行时管理的——在我们的例子中是 PHP 运行时。它们是管理某些形式的并行编程的一种经济高效的方式。

但请注意,它们并没有添加任何真正的异步内容:所有纤程都位于同一个 PHP 进程中,并且一次只能运行一个纤程。这是循环它们并在等待时检查它们的主进程,该循环通常称为“事件循环”。

并行性的难点不在于你如何在纤程或生成器上循环,或者你想使用的任何机制;它是关于能够开始一个 *** 作,将它交给一个外部服务,并且只在你想要的时候以非阻塞的方式检查结果。

看,在前面的例子中,我们假设我们可以只发送一个请求,然后在我们想要的时候检查它的响应,但这实际上并不像听起来那么容易。

没错:大多数处理 I/O 的 PHP 函数都没有内置这种非阻塞功能。事实上,只有少数函数可以做到,而且使用它们非常麻烦。

有一个套接字的例子,它可以被设置为非阻塞,像这样:

[$read, $write] = stream_socket_pair(
    STREAM_PF_UNIX,
    STREAM_SOCK_STREAM,
    STREAM_IPPROTO_IP
);
 
stream_set_blocking($read, false);
stream_set_blocking($write, false);

通过使用stream_socket_pair(),创建了两个可用于双向通信的套接字。正如您所看到的,它们可以使用stream_set_blocking().

假设我们想要实现我们的示例,发送三个请求。我们可以使用套接字来做到这一点,但我们需要在它之上自己实现 HTTP 协议。这正是nox7所做的,该用户在Reddit上分享了一个小型概念证明,以展示如何使用光纤和套接字发送 HTTP GET 请求。你真的想在你的应用程序代码中这样做吗?

至少对我来说,答案是“不”。这正是 RFC 警告的内容;我不生气。相反,我们鼓励使用现有的异步框架之一:Amp或ReactPHP。

例如,使用 ReactPHP,我们可以这样写:

$loop = React\EventLoop\Factory::create();
$browser = new Clue\React\Buzz\Browser($loop);
$promises = [
    $browser->get('https://example.com/1'),
    $browser->get('https://example.com/2'),
    $browser->get('https://example.com/3'),
];
$responses = Block\awaitAll($promises, $loop);

与手动创建套接字连接相比,这是一个更好的示例。这就是 RFC 的意思:应用程序开发人员不需要担心纤程,它是 Amp 或 ReactPHP 等框架的实现细节。

不过,这给我们带来了一个问题:与我们已经可以用发电机做的事情相比,纤维有什么好处?RFC 是这样解释的:

与无堆栈生成器不同,每个 Fiber 都有自己的调用堆栈,允许它们在深度嵌套的函数调用中暂停。声明中断点的函数(即调用 Fiber::suspend())不需要更改其返回类型,这与使用 yield 的函数必须返回 Generator 实例不同。

Fiber 可以在任何函数调用中挂起,包括那些从 PHP VM 内部调用的函数,例如提供给 array_map 的函数或迭代器对象上的 foreach 调用的方法。

很明显,纤程在语法和灵活性方面都有显着的改进。但与 Go 及其“ goroutines ”相比,它们还不算什么。

要使异步 PHP 在没有框架开销的情况下成为主流,仍然缺少许多功能,而 Fiber 是朝着正确方向迈出的良好一步,但我们还没有做到这一点。

所以就是这样。如果您不是 Amp、ReactPHP 或较小的异步 PHP 框架的维护者,那么实际上没有什么可说的。也许更多的框架或库将开始合并它们?

同时,还有Swoole——一个 PHP 扩展,它实际上将几个核心功能修改为非阻塞。Swoole 本身是一个中文项目,在涉及英语时通常没有很好的文档记录,但最近 Laravel宣布与它进行第一方集成。也许这是将 PHP 推向更异步模型的更好策略:可选择将 Swoole 或其他扩展与 Laravel 和 Symfony 等框架集成?

以上就是PHP8.1新特性大讲解之Fibers with a grain of salt的详细内容,

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/679063.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-19
下一篇 2022-04-19

发表评论

登录后才能评论

评论列表(0条)

保存