探索异步 PHP

本文探讨了在 PHP 中实现异步编程的不同方法,包括使用 `exec()`、`pcntl_fork()`、AMPHP 库以及队列和工作者。随着 PHP 8.1 引入 fibers,异步编程的未来更加令人期待。文章通过实例展示了各种方法的优缺点,强调了在选择解决方案时要考虑的因素。
摘要由CSDN通过智能技术生成

由于越来越需要在每个 Web 请求中执行更多操作,因此异步编程是扩展 Web 应用程序的基础构建块。一个典型的例子是发送电子邮件作为请求的一部分。

在许多 Web 应用程序中,当服务器上处理某些内容时,我们希望通过电子邮件通知人们,这通常是对第三方服务(如 SendGrid、Mailchimp 等)的单独 HTTP 请求。

当您需要一次发送大量电子邮件时,这将成为一个非常简单的示例。在 PHP 中,如果您要发送电子邮件并且 HTTP 过程需要 100 毫秒才能完成,那么您将通过发送数十或数百封电子邮件来快速增加请求的总时间。

当然,任何优秀的第三方电子邮件服务都会提供一个批量端点来否定这一点,但为了举例 - 假设您要发送 100 封电子邮件,并且每封电子邮件都必须单独处理。

因此,我们需要做出决定:我们如何才能将电子邮件的处理转移到一个单独的进程中,以便它不会阻止原始 Web 请求?
这就是我们将在本文中探索的内容,特别是在有或没有新基础架构的情况下可以在 PHP 中解决的所有不同方法。

使用 exec()
exec()是 PHP 中的原生函数,可用于执行外部程序并返回结果。在我们的例子中,它可能是一个发送电子邮件的脚本。这个函数使用操作系统来生成一个全新的(空白的,没有复制或共享的)进程,你可以将任何你需要的状态传递给它。

让我们看一个例子。

<?php
// handle a web request

// record the start time of the web request
$start = microtime(true);
$path = __DIR__ . '/send_email.php';

// output to /dev/null & so we don't block to wait for the result
$command = 'php ' . $path . ' --email=%s > /dev/null &';
$emails = ['joe@blogs.com', 'jack@test.com'];

// for each of the emails, call exec to start a new script
foreach ($emails as $email) {
   
    // Execute the command
    exec(sprintf($command, $email));
}

// record the finish time of the web request
$finish = microtime(true);
$duration = round($finish - $start, 4);

// output duration of web request
echo "finished web request in $duration\n";

发送电子邮件.php

<?php

$email = explode('--email=', $argv[1])[1];
// this blocking sleep won't affect the web request duration
// (illustrative purposes only)
sleep(5);

// here we can send the email
echo "sending email to $email\n";

输出

$ php src/exec.php

finished web request in 0.0184

上面的脚本显示 Web 请求仍然在几毫秒内完成,即使sleep在 send_email.php 脚本中有一个阻塞函数调用。

它不阻塞的原因是因为我们已经在命令中包含exec我们> /dev/null &不想等待exec命令完成所以我们可以获得结果,这意味着它可以在后台和网络请求中发生可以继续。

这样,Web 请求脚本只负责运行脚本,而不是监视其执行和/或失败。

这是该解决方案固有的缺点,因为流程的监控落在流程本身上并且无法重新启动。但是,这是一种无需太多努力即可将异步行为引入 PHP 应用程序的简单方法。

exec在服务器上运行命令,因此您必须注意脚本的执行方式,尤其是当它涉及用户输入时。它可能很难管理,exec尤其是当您管理应用程序的扩展时,因为脚本可能运行在处理外部 Web 请求的同一个机器上,所以如果有数百或数千个新进程,您最终可能会耗尽 CPU 和内存产生于exec.

pcntl_fork
pcntl_fork是一个低级函数,需要启用 PCNTL 扩展,它是一种功能强大但可能容易出错的方法,用于在 PHP 中编写异步代码。

pcntl_fork将分叉或克隆当前进程并将其拆分为一个父进程和多个子进程(取决于它被调用的次数)。通过检测进程 ID 或 PID,我们可以在父进程或子进程的上下文中运行不同的代码。

父进程将负责生成子进程并等待生成的进程完成后才能完成。

在这种情况下,我们可以更好地控制进程如何退出,并且可以轻松地编写一些逻辑来处理子进程失败时的重试。

现在,转到我们用例的示例代码,以非阻塞方式发送电子邮件。

<?php

function sendEmail($to, $subject, $message)
{
   
    // Code to send email (replace with your email sending logic)
    // This is just a mock implementation for demonstration purposes
    sleep(3); // Simulating sending email by sleeping for 3 seconds
    echo "Email sent to: $to\n";
}

$emails = [
    [
        'to' => 'john@example.com',
        'subject' => 'Hello John',
        'message' => 'This is a test email for John.',
    ],
    [
        'to' => 'jane@example.com',
        'subject' => 'Hello Jane',
        'message' => 'This is a test email for Jane.',
    ],
    // Add more email entries as needed
];

$children = []
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q shen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值