dima-bzz/fork

PHP中运行代码并行的轻量级解决方案

资助包维护!
spatie

1.1.2 2021-12-18 16:19 UTC

This package is auto-updated.

Last update: 2024-09-18 22:20:59 UTC


README

Latest Version on Packagist Tests GitHub Code Style Action Status Total Downloads

此包使得运行PHP并发变得简单。在幕后,通过为主PHP进程创建一个或多个子任务来实现并发。

在此示例中,我们将调用一个假设的慢速API,所有三个闭包将同时运行。

use Spatie\Fork\Fork;

$results = Fork::new()
    ->run(
        fn () => (new Api)->fetchData(userId: 1),
        fn () => (new Api)->fetchData(userId: 2),
        fn () => (new Api)->fetchData(userId: 3),
    );

$results[0]; // fetched data of user 1
$results[1]; // fetched data of user 2
$results[2]; // fetched data of user 3

内部工作原理

✨ 在YouTube上的视频中,我们解释了该包的内部工作原理。

支持我们

我们投入了大量资源来创建一流的开放式源代码包。您可以通过购买我们的付费产品之一来支持我们。

我们非常感谢您从您的家乡给我们寄来明信片,说明您正在使用我们哪些包。您可以在我们的联系页面上找到我们的地址。我们将发布所有收到的明信片在我们的虚拟明信片墙上

要求

此包需要PHP 7.4或更高版本以及pcntl扩展,该扩展默认安装在许多Unix和Mac系统上。

❗️ pcntl仅在工作进程的CLI进程中工作,不在Web环境中工作。

安装

您可以通过composer安装此包

composer require dima-bzz/fork

使用方法

您可以将任意数量的闭包传递给run。它们将并发运行。run函数将返回一个包含执行闭包的返回值的数组。

use Spatie\Fork\Fork;

$results = Fork::new()
    ->run(
        function ()  {
            sleep(1);

            return 'result from task 1';
        },
        function ()  {
            sleep(1);

            return 'result from task 2';
        },
        function ()  {
            sleep(1);

            return 'result from task 3';
        },
    );

// this code will be reached this point after 1 second
$results[0]; // contains 'result from task 1'
$results[1]; // contains 'result from task 2'
$results[2]; // contains 'result from task 3'

在每个闭包前后运行代码

如果您需要在每个传递给run的可调用函数之前或之后执行一些代码,您可以将一个可调用函数传递给beforeafter方法。此传递的可调用函数将在子进程中执行,在传递给run的可调用函数之前或之后。

在子任务中使用beforeafter

以下是一个示例,我们将使用Laravel Eloquent模型从数据库中获取值。为了使子任务使用DB,必须重新连接到DB。传递给before的闭包将在为传递给run的闭包创建的所有子任务中运行。

use App\Models\User;
use Illuminate\Support\Facades\DB;
use Spatie\Fork\Fork;

 Fork::new()
    ->before(fn () => DB::connection('mysql')->reconnect())
    ->run(
        fn () => User::find(1)->someLongRunningFunction(),
        fn () => User::find(2)->someLongRunningFunction(),
    );

如果您需要在子任务的可调用函数运行后执行一些清理工作,您可以在一个Spatie\Fork\Fork实例上使用after方法。

在父任务中使用beforeafter

如果您需要让传递给beforeafter的可调用函数在父任务中运行,则需要将该可调用函数传递给parent参数。

use App\Models\User;
use Illuminate\Support\Facades\DB;
use Spatie\Fork\Fork;

 Fork::new()
    ->before(
        parent: fn() => echo 'this runs in the parent task'
    )
    ->run(
        fn () => User::find(1)->someLongRunningFunction(),
        fn () => User::find(2)->someLongRunningFunction(),
    );

您还可以传递不同的闭包,以在子任务和父任务中运行

use Spatie\Fork\Fork;

Fork::new()
    ->before(
        child: fn() => echo 'this runs in the child task',
        parent: fn() => echo 'this runs in the parent task',
    )
    ->run(
        fn () => User::find(1)->someLongRunningFunction(),
        fn () => User::find(2)->someLongRunningFunction(),
    );

返回数据

所有输出数据都收集到一个数组中,并在所有子任务完成后立即可用。在此示例中,$results将包含三个项目

$results = Fork::new()
    ->run(
        fn () => (new Api)->fetchData(userId: 1),
        fn () => (new Api)->fetchData(userId: 2),
        fn () => (new Api)->fetchData(userId: 3),
    );

输出也在after回调中可用,每当子任务完成时就会调用,而不仅仅是最后

$results = Fork::new()
    ->after(
        child: fn (int $i) => echo $i, // 1, 2 and 3
        parent: fn (int $i) => echo $i, // 1, 2 and 3
    )
    ->run(
        fn () => 1,
        fn () => 2,
        fn () => 3,
    );

最后,使用PHP内置的serialize方法对子任务的返回值进行序列化。这意味着你可以返回在PHP中通常可以序列化的任何内容,包括对象。

$result = Fork::new()
    ->run(
        fn () => new DateTime('2021-01-01'),
        fn () => new DateTime('2021-01-02'),
    );

配置并发

默认情况下,所有可调用函数都会并行运行。然而,你可以配置并发进程的最大数量。

$results = Fork::new()
    ->concurrent(2)
    ->run(
        fn () => 1,
        fn () => 2,
        fn () => 3,
    );

在这种情况下,前两个函数将立即运行,一旦其中一个完成,最后一个也将开始运行。

测试

composer test

变更日志

有关最近更改的更多信息,请参阅变更日志

贡献

有关详细信息,请参阅贡献指南

安全漏洞

请查阅我们的安全策略以了解如何报告安全漏洞。

鸣谢

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件