在 PHP 中使用异步进程。

2025-06-07

在 PHP 中使用异步进程。

对于大多数用 PHP 编写的程序来说,其唯一目的是执行一个由多个任务组成的简单进程,这些任务必须按顺序执行,例如数据处理。我们总是不得不忍受同步编程的停止和等待。同步代码执行被称为阻塞,这意味着任务将逐个执行。那么,如果我们想在运行任务时避免它们相互阻塞,那该怎么办呢?这意味着我们需要一个非阻塞进程。这种方法需要在 PHP 中应用异步编程方法,此时任务将彼此不依赖地执行。

在 PHP 中实现非阻塞执行的常用方法是实现队列处理。任务会被持久化到传输系统(例如 MySQL、Redis、Amazon SQS 等),由后台工作进程检索并执行,从而不会阻塞创建任务的主进程。Laravel 应用程序提供了一种队列机制,允许将任务(此处称为作业)延迟到以后再处理。

另一种方法是并行运行所有已定义的任务。这种方法的好处是,当特定任务完成后,它可以立即将控制权交还给主进程,并承诺执行代码,并在稍后通知我们结果(例如回调)。并行处理方法的用例可能很少;例如,执行图像处理并向某个外部服务发出获取请求。

让我们通过一个非常简单的用例来看一下 PHP 中同步和异步(并行)进程之间的区别。

同步代码

  foreach (range(1, 5) as $i) {
     $output = $i * 2;
     echo $output . "\n";
  }
Enter fullscreen mode Exit fullscreen mode

异步代码

    use Spatie\Async\Pool;

    $pool = Pool::create();

    foreach (range(1, 5) as $i) {
        $pool[] = async(function () use ($i) {
           $output = $i * 2;
           return $output;
        })->then(function (int $output) {
           echo $output . "\n";
        });
    }
    await($pool);
Enter fullscreen mode Exit fullscreen mode

当我们执行第一个代码时,我们将按以下顺序获得输出值:

2
4
6
8
10
Enter fullscreen mode Exit fullscreen mode

重试执行,我们将得到与上面相同的输出序列……因此,每个乘法运算都会等待执行,然后再执行下一个。接下来,运行第二个代码块,看看会得到什么。

6
10
2
8
4
Enter fullscreen mode Exit fullscreen mode

第二次重试执行:

2
6
4
10
8
Enter fullscreen mode Exit fullscreen mode

一个进程恰好产生了两种不同的结果。这正是我们利用异步方法所获得的……我们的小任务可以以互不阻塞的方式执行。每个乘法任务独立执行,有些任务执行得比其他任务快,因此输出结果比较无序。另外,请注意我们的 async 函数附加了一个 then 方法,该方法负责收回控制权,并接受一个回调函数作为参数,该回调函数现在可以对接收到的输出执行额外的操作。

Spatie 的朋友们制作了这个很棒的spatie/async包,它有助于并行执行任务。您可以通过 composer 安装它:

composer require spatie/async
Enter fullscreen mode Exit fullscreen mode

该包提供了一种简洁的方式来与创建的并行执行任务进行交互。任务的事件监听器如下所述:

  • 通过其方法,可以在任务完成时通过回调执行另一个操作then
  • 当特定任务使用该方法抛出异常时,错误处理更容易控制catch
  • 比如说,一个任务没有完成其操作,一种timeout方法可以处理这种情况。

事件监听器与任务挂钩,如下所示:

    $pool
        ->add(function () {
            // Task to be performed in a Parallel process
        })
        ->then(function ($output) {
            // On success, `$output` is returned by the process or callable you passed to           the queue.
        })
        ->catch(function ($exception) {
            // When an exception is thrown from within a process, it's caught and passed here.
        })
        ->timeout(function () {
            // Ohh No! A process took too long to finish. Let's do something 
        })
    ;
Enter fullscreen mode Exit fullscreen mode

要了解有关该软件包的更多信息,请阅读其中spatie/async一位贡献者撰写的这篇文章,您也可以参考GitHub repo

文章来源:https://dev.to/webong/using-asynchronous-processes-in-php-7io
PREV
Web3 社区简介
NEXT
使用 Webiny Serverless Headless CMS、Next.js 和 Stripe 构建电子商务网站