swoole|swoole_process源码分析之process创建过程

swoole提供了创建进程的方式,据swoole官方文档介绍,比PHP原生的pcntl更高效,下面是官方文档给出的pcntl的缺点和swoole的优点。
PHP自带的pcntl,存在很多不足,如

  • pcntl没有提供进程间通信的功能
  • pcntl不支持重定向标准输入和输出
  • pcntl只提供了fork这样原始的接口,容易使用错误
  • swoole_process提供了比pcntl更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。
swoole_process提供了如下特性:
  • swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可
  • swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据
  • 配合swoole_event模块,创建的PHP子进程可以异步的事件驱动模式
  • swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信。
从这篇文章开始,我们开始分析下swoole的进程控制模块,其代码位于swoole_process.c中,现在我们就从一个PHP的使用demo开始。
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创建过程】

    推荐阅读