头图

PHP 多进程任务 spatie/async 扩展使用说明

spatie/async 是为 PHP 基于 PCNTL 扩展开发的,能够使用多进程处理任务。

项目地址

spatie/async

常规使用示例

对象形式

use Spatie\Async\Pool;

$pool = Pool::create()
// 选择执行 PHP
->withBinary('/path/to/php')
// 可同时运行的最大进程数
->concurrency(20)
// 进程完成所需的最长时间(以秒为单位),支持小数点位置以实现更细粒度的超时
->timeout(15)
// 配置应该使用哪个自动加载器子流程
->autoload(__DIR__ . '/../../vendor/autoload.php')
// 配置循环应该休眠多长时间,然后重新检查进程状态(以微秒为单位)。
->sleepTime(50000);

foreach ($things as $thing) {
    $pool->add(function () use ($thing) {
        // 添加任务
    })->then(function ($output) {
        // 任务执行完毕回调函数,返回结果会以变量 $output 注入回调函数

        // $pool->stop(); 提前终止 pool 任务池执行,终止后想要继续使用则需要重新创建任务池
    })->catch(function (MyException $e) {
        // 捕捉异常
    })
    ->catch(function (Exception $e) {
        // / 捕捉异常,支持不做多个
    })->timeout(function () {
        // 超时处理
    });
}
$pool->wait();

函数使用方式

use Spatie\Async\Pool;

$pool = Pool::create();

foreach (range(1, 5) as $i) {
    $pool[] = async(function () {
        usleep(random_int(10, 1000));
        return 2;
    })->then(function (int $output) {
        echo $output.PHP_EOL;
    });
}

await($pool);

任务类使用方式

需要创建任务类,并继承类 Spatie\Async\Task,任务执行会调用 task 任务类的 run() 方法

use Spatie\Async\Task;

class MyTask extends Task
{
    public function configure()
    {
        // 加载配置,如:依赖容器、核心类加载
    }

    public function run()
    {
        // 任务工作程序
    }
}

// Add the task to the pool
$pool = Pool::create();
$pool->add(new MyTask());
$pool->wait();

补充:在 Laravel 中使用注意

如果没有加载 bootstrap/app.php 配置,则无法使用 Laravel 提供的类方法。比如:使用 Illuminate\Support\Facades\Log 时会报异常 Exception: A facade root has not been set

未加载 bootstrap/app.php 示例

<?php
namespace App\Task;

use Spatie\Async\Task;
use Illuminate\Support\Facades\Log;

class EmployTask extends Task
{
    public function configure()
    {
    }

    public function run()
    {
        $datetime = date('Y-m-d H:i:s');
        Log::error('EmployTask',['type' => 'use Log','msg' => '未加载 bootstrap/app.php', 'datetime' => $datetime]);
    }
}

报错信息如下

[2022-03-28 17:26:17] local.ERROR: EmployTask {"msg":"A facade root has not been set.

#0 /www/wwwroot/laravel/app/Task/EmployTask.php(23): Illuminate\\Support\\Facades\\Facade::__callStatic()
#1 /www/wwwroot/laravel/app/Task/EmployTask.php(17): App\\Task\\EmployTask->test()
#2 /www/wwwroot/laravel/vendor/spatie/async/src/Task.php(15): App\\Task\\EmployTask->run()
#3 /www/wwwroot/laravel/vendor/spatie/async/src/Runtime/ChildRuntime.php(26): Spatie\\Async\\Task->__invoke()
#4 {main}"} 

加载 bootstrap/app.php 示例

<?php
namespace App\Task;

use Spatie\Async\Task;
use Illuminate\Support\Facades\Log;

class EmployTask extends Task
{
    public function configure()
    {
        $app = require __DIR__.'/../../bootstrap/app.php';
        $kernel = $app->make(\Illuminate\Contracts\Console\Kernel::class);
        $kernel->bootstrap();
    }

    public function run()
    {
        $datetime = date('Y-m-d H:i:s');
        Log::error('EmployTask',['type' => 'use Log','msg' => '加载 bootstrap/app.php', 'datetime' => $datetime]);
    }
}


// 也可以这样使用

$pool[] = async(function () use ($result, $syncemployRepository) {
    $app = require __DIR__.'/../../../../bootstrap/app.php';
    $kernel = $app->make(\Illuminate\Contracts\Console\Kernel::class);
    $kernel->bootstrap();
    // 任务代码
})->then(function ($output) use($pool) {
    $pool->stop();
})->catch(function (Exception $e) {
    Log::error('createauth_sync', ['msg' => $e->getMessage()]);
});

记录日志如下

[2022-03-28 17:28:26] local.ERROR: EmployTask {"type":"use Log","msg":"加载 bootstrap/app.php","datetime":"2022-03-28 17:28:26"} 

原因说明

作者在文档中有说明 Besides using closures, you can also work with a Task. A Task is useful in situations where you need more setup work in the child process. Because a child process is always bootstrapped from nothing, chances are you'll want to initialise eg. the dependency container before executing the task. The Task class makes this easier to do.(除了可以使用闭包,还可以使用 Task 任务。使用者有可能需要在子进程中加载更多设置。子进程总是从零开始启动的,所以就需要进行初始化。比如:加载依赖容器、核心类)

Hello World!

10 声望
2 粉丝
0 条评论
推荐阅读
Alibaba 数据库迁移开源工具 Datax 安装和使用
事情是这样的,服务商有一批数据,现在的数据量大致为 2 千万条(单表),每天都会增加数据(增加多少暂不知道),但是呢给我们提供的查询不是一张数据表而是一张视图,我们再根据这个数据对外提供一个查询服务。...

其名阅读 432

封面图
怎样用 PHP 来实现枚举?
在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。枚举是一个被命名的整型常数的集合,枚举在日常生活中很常见,...

唯一丶25阅读 6.3k评论 4

图片防盗链破解 解决图片防盗链问题 反向代理
当客户端(浏览器)向服务器请求内容的时候,会提交一个header,这个header中包含了如:浏览器信息、cookie等内容,那么有一个叫referer的东东,也包含在这里面。

TANKING7阅读 11.2k评论 5

Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 2k评论 2

封面图
微信公众号开发:自动回复文本/图片/图文消息/关键词回复/上传素材/自定义菜单
对接流程1、申请微信公众号测试账号URL:[链接]2、登录,配置开发者服务器URL和Token开发者服务器配置代码:config.php {代码...} URL是config.php在你服务器的URLToken是上面代码自己设置的Token搞定之后,就能完...

TANKING2阅读 10k

PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go4阅读 944评论 2

封面图
Ajax实现搜索联想 搜索关键词提醒 无刷新搜索
通过javascript监听搜索框的内容,调用后端即可。(1)javascript监听搜索框的内容(2)把搜索框的关键词传给后端进行搜索(3)搜索到结果,遍历到页面

TANKING1阅读 4.3k

Hello World!

10 声望
2 粉丝
宣传栏