在平行空间中运行程序

介绍

思考这样一个实例:老师答疑时要下发通知给学员的App。把老师提交的答案保存到数据库只需50ms,调用第三方的WebService接口完成推送却需要等待500ms乃至数秒!我们希望老师可以马上看到答案提交成功,并且开始为下一位学员答疑,不必等待App推送完成。x2ts框架提供了一个新的功能来达成这一目的,你可以提交一段代码,让这段代码在独立的进程中运行,不会阻塞php-fpm。用起来就像这样:

X::parallel(function($userId, $title, $message) {
    $ret = X::curl->post(...); //请求推送接口
    X::logger()->info($ret);
})->run(
    $askSubject->user_id,
    $askSubject->author . '回答了你的问题',
    $askSubject->first_ask
);

例子中的代码把调用推送接口的代码写在了一个匿名函数中,然后调用run方法把参数传过去,这个匿名函数会在另一个进程中运行。这里的“另一个进程”,就是Parallel Runner的守护进程。

使用说明

想要使用Parallel Runner首先要用composer引入库:

composer require x2ts/x2ts-parallel

然后在配置文件中加入组件配置:

'parallel'     => [
    'class'     => \x2ts\parallel\Runner::class,
    'singleton' => true,
    'conf'      => [
        'name'       => 'sk-parallel',
        'sock'       => '/var/run/sk/parallel.sock',
        'pid'        => '/var/run/sk/parallel.pid',
        'lock'       => '/var/run/sk/parallel.lock',
        'workerNum'  => 16,
        'backlog'    => 128,
        'maxRequest' => 500,
    ],
],

X类中加入parallel方法申明

/**
 * @method static x2ts\parallel\Runner parallel(Closure $func = null)
 */
class X extends x2ts\ComponentFactory {}

编写Parallel Runner启动脚本:

<?php
// cliroot/parallel.php
require_once dirname(__DIR__) . '/webroot/xts.php';
X::parallel()->start();

最后,启动Parallel Runner守护进程:

mkdir /var/run/sk
chown -R www-data:www-data /var/run/sk
php cliroot/parallel.php

现在就可以像前面的例子一样,把程序放到Parallel Runner中运行了。

限制

因为匿名函数其实是在Parallel Runner进程中运行,所以必然会有一些限制:

  1. 不能使用use关键字引入外层变量,因为在另一个进程中没有此匿名函数的执行上下文。
  2. 不能使用$this变量,理由和上一条相同,但可以在内部的匿名类定义中使用$this,此时$this指向该匿名类的实例。
  3. 不能按引用传递变量,因为变量实际会通过IPC的方式发到另一个进程,按引用传递变量是没有意义的。
  4. 不能传递不可被序列化的变量,因为要通过IPC的方式发送到另一进程,resource和不可序列化的object不能作为参数传递。
  5. 不能期待返回值,因为程序在另一个进程中运行,执行结果只能通过修改数据库、Redis等方式反映,所有return的数据都会被丢弃。
  6. 不能期待echo输出,因为程序在另一个进程中运行,echo输出的内容并不会显示在页面上,因为是守护进程,也不会输出到屏幕,需要输出信息供阅读和调试,请通过日志输出。

标签: x2ts, parallel, async

添加新评论