在平行空间中运行程序
介绍
思考这样一个实例:老师答疑时要下发通知给学员的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进程中运行,所以必然会有一些限制:
- 不能使用
use
关键字引入外层变量,因为在另一个进程中没有此匿名函数的执行上下文。 - 不能使用
$this
变量,理由和上一条相同,但可以在内部的匿名类定义中使用$this
,此时$this
指向该匿名类的实例。 - 不能按引用传递变量,因为变量实际会通过
IPC
的方式发到另一个进程,按引用传递变量是没有意义的。 - 不能传递不可被序列化的变量,因为要通过
IPC
的方式发送到另一进程,resource
和不可序列化的object
不能作为参数传递。 - 不能期待返回值,因为程序在另一个进程中运行,执行结果只能通过修改数据库、Redis等方式反映,所有
return
的数据都会被丢弃。 - 不能期待echo输出,因为程序在另一个进程中运行,echo输出的内容并不会显示在页面上,因为是守护进程,也不会输出到屏幕,需要输出信息供阅读和调试,请通过日志输出。