swoole提供了创建进程的方式,据swoole官方文档介绍,比PHP原生的pcntl更高效,下面是官方文档给出的pcntl的缺点和swoole的优点。
PHP自带的pcntl,存在很多不足,如
- pcntl没有提供进程间通信的功能
- pcntl不支持重定向标准输入和输出
- pcntl只提供了fork这样原始的接口,容易使用错误
- swoole_process提供了比pcntl更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。
- swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可
- swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据
- 配合swoole_event模块,创建的PHP子进程可以异步的事件驱动模式
- swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信。
start();
function callback_function(swoole_process $worker)
{
$worker->exec('/usr/local/bin/php', array(__DIR__.'/swoole_server.php'));
}swoole_process::wait();
代码我们就从swoole_process的构造函数开始。
//swoole_process的构造函数,从PHP代码可以看出,其构造函数可以传入进程执行函数、标准输出和错误的重定向信息、是否使用管道以及管道类型
static PHP_METHOD(swoole_process, __construct)
{
zend_bool redirect_stdin_and_stdout = 0;
long pipe_type = 2;
zval *callback;
//这种模式仅仅适用于cli模式
if (!SWOOLE_G(cli))
{
swoole_php_fatal_error(E_ERROR, "swoole_process only can be used in PHP CLI mode.");
RETURN_FALSE;
}
//swoole_process不适用于master进程,这里主要是由于master进程牵涉多线程的操作,这里的master进程是指swoole_server里面的master进程
if (SwooleG.serv && SwooleG.serv->gs->start == 1 && swIsMaster())
{
swoole_php_fatal_error(E_ERROR, "swoole_process can't be used in master process.");
RETURN_FALSE;
}//不支持异步IO
if (SwooleAIO.init)
{
swoole_php_fatal_error(E_ERROR, "unable to create process with async-io threads.");
RETURN_FALSE;
}//解析输入参数信息,输入参数如上面所说的三个
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bl", &callback, &redirect_stdin_and_stdout, &pipe_type) == FAILURE)
{
RETURN_FALSE;
}//判断callback信息是否是可以执行的
char *func_name = NULL;
if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC))
{
swoole_php_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
efree(func_name);
RETURN_FALSE;
}
efree(func_name);
//申请swWorker空间及初始化
swWorker *process = emalloc(sizeof(swWorker));
bzero(process, sizeof(swWorker));
int base = 1;
if (SwooleG.serv && SwooleG.serv->gs->start) //确定worker的编号信息,这里和swoole_server结合一起确定其ID信息
{
base = SwooleG.serv->worker_num + SwooleG.serv->task_worker_num + SwooleG.serv->user_worker_num;
}
if (php_swoole_worker_round_id == 0)//如果没有ID,则该ID设置为1
{
php_swoole_worker_round_id = base;
}
process->id = php_swoole_worker_round_id++;
//ID赋值信息if (redirect_stdin_and_stdout)//需要重定向,这里所谓的重定向是指标准输出和错误输出不再显示到屏幕上,而是写到管道中。
{
process->redirect_stdin = 1;
process->redirect_stdout = 1;
process->redirect_stderr = 1;
/**
* Forced to use stream pipe
*/
pipe_type = 1;
//管道信息设置
}if (pipe_type > 0)//使用管道
{
swPipe *_pipe = emalloc(sizeof(swPipe));
int socket_type = pipe_type == 1 ? SOCK_STREAM : SOCK_DGRAM;
if (swPipeUnsock_create(_pipe, 1, socket_type) < 0) //创建管道信息
{
RETURN_FALSE;
}process->pipe_object = _pipe;
//设置进程的管道对象信息
process->pipe_master = _pipe->getFd(_pipe, SW_PIPE_MASTER);
//创建管道的master描述符信息
process->pipe_worker = _pipe->getFd(_pipe, SW_PIPE_WORKER);
//创建管道的worker描述符信息
process->pipe = process->pipe_master;
//设置swoole_process的属性
zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("pipe"), process->pipe_master TSRMLS_CC);
}swoole_set_object(getThis(), process);
//创建PHP侧对象swoole_process和内部对象的对应关系
zend_update_property(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("callback"), callback TSRMLS_CC);
//设置swoole_process的属性
}
【swoole|swoole_process源码分析之process创建过程】
推荐阅读
- php|php+swoole实现群聊
- php swoole-http_server
- swoole|PHP Swoole与TCP四次挥手
- PHP|TP5集成Swoole
- ThinkPHP|Swoole整合ThinkPHP3.2系列教程六
- php|mac上phpinfo()可以看到swoole模块但是提示swoole_server(class no found)
- HTTPS站点使用WebSocket的常见错误及解决方案
- Swoole之环境安装