二十四、Swoole 基础学习笔记 - Swoole Process 单进程

作者: 温新

分类: 【Swoole 系列】

阅读: 666

时间: 2023-03-13 11:52:26

hi,我是温新,一名PHPer

文章基于 Swoole 5.0.1 版本编写。

学习目标:学习 Process 基础使用

说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!

Swoole 进程模块

Swoole 自己实现了一套进程管理模块,用于替代 PHP 的 pcntl

PHP 中已有 pcntl,为什么 Swoole 要自己搞一套?因为 PHP 自带的 pcntl 存在很多不足,如:

  • 1、没有提供进程间通信的功能;
  • 2、不支持重定向标准输入和输出;
  • 3、只提供 fork 原始接口,容易使用错误。

基于 pcntl 存在这些问题,Swoole Process 提供了如下特性:

  • 可以方便的实现进程间通讯;
  • 支持重定向标准输入和输出,在子进程内 echo 不会打印在屏幕中,而是写入管道,读键盘输入可以重定向为管道读取数据;
  • 提供 exec 接口,创建的进程可以执行其他程序,与原 PHP 父进程之间可以方便的通信;
  • 在协程环境中无法使用 Process 模块,可以使用 runtime hook + proc_open 实现。

进程间通信

我们知道进程与进程之间是相互隔离,执行任务时,进程之间互不影响。在实际开发中,很多业务之间需要进程通信,如发送邮件,若子进程发送邮件失败,需要通知主进程等等。

Swoole Process 基础使用

process 开胃甜点案例

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 24-swoole-process-base-1.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Process</span>(<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'process_callback'</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">process_callback</span> () {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">    echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Swoole Process'</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">start</span>();</span>

对于代码暂时不进行解释,先来看看输出的结果:

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Swoole Process[codeing@codeing]<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$php</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">24</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">-swoole-process-base-1</span>.php </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">[codeing@codeing]<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$Swoole</span> Process</span>

为什么会一前一后?这就需要了解 Swoole Process 实现的进程创建了。如子进程没有结束前,父进程已经退出了,因此输出的形式也就不一样了。父子进程如何区分?

  • new Swoole\Process 为进程;
  • process_callback 回调函数是子进程。

process 基础案例

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 24-swoole-process-2.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 创建进程(父进程)</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Process</span>(<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'process_callback'</span>);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 子进程</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">process_callback</span> () {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">    echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Swoole Process'</span> . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">}</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 启动子进程</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">start</span>();</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 子进程结束后父进程再退出</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 操作成功会返回一个数组包含子进程的 PID、退出状态码、被哪种信号 KILL</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Process</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">wait</span>();</span>

输出结果如下:

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$php</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">24</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">-swoole-process-base-2</span>.php </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Swoole Process</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$php</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">24</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">-swoole-process-base-2</span>.php </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Swoole Process</span>

现在无论怎么输出,输出的显示都是一样的,原因是使用了 wait 方法。现在学习相关方法:

__construct

<span style="color: rgb(0, 176, 240);">Swoole\Process::__construct(callable $function, bool $redirect_stdin_stdout = false, int $pipe_type = SOCK_DGRAM, bool $enable_coroutine = false);</span><br></br>

参数:

  • function:子进程创建成功后要执行的函数;
  • redirect_stdin_stdout:重定向子进程的标准输入和输出。【启用此选项后,在子进程内输出内容将不是打印屏幕,而是写入到主进程管道。读取键盘输入将变为从管道中读取数据。默认为阻塞读取。】
  • pipe_type:unixSocket 类型。【启用 $redirect_stdin_stdout 后,此选项将忽略用户参数,强制为 1。如果子进程内没有进程间通信,可以设置为 0
  • enable_coroutine:在 callback function 中启用协程,开启后可以直接在子进程的函数中使用协程 API。

start

含义:执行 fork 系统调用,启动子进程。在 Linux 系统下创建一个进程需要数百微秒时间。

返回值:成功返回子进程的 PID;失败返回 false。

<span style="color: rgb(0, 176, 240);">Swoole\Process->start(): int|false</span><br></br>

wait

含义:回收结束运行的子进程。

返回值:操作成功会返回一个数组包含子进程的 PID、退出状态码、被哪种信号 KILL;失败返回 false。

<span style="color: rgb(0, 176, 240);">Swoole\Process::wait(bool $blocking = true): array|false</span><br></br>

exec

含义:执行一个外部程序,此函数是 exec 系统调用的封装。

<span style="color: rgb(0, 176, 240);">Swoole\Process->exec(string $execfile, array $args);</span><br></br>

参数:

  • execfile:指定可执行文件的绝对路径,如: /usr/local/php/bin/php;
  • args:exec 的参数列表。

process 执行外部程序

执行外部程序使用 exce 方法。

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 24-swoole-process-base-exce.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span> <span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">=</span> <span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">new</span> <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Process</span>(<span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">function</span> (<span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$worker</span>) {</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">    // 执行一个外部程序</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">    $worker</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(232, 191, 106) !important">exec</span>(<span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'/usr/local/php8/bin/php'</span>, [<span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">__DIR__</span> . <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'/24-exec.php'</span>]);</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">});</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 启动子进程</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">start</span>();</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 获取子进程必须在 start() 之后</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'子进程 ID '</span> . <span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$process</span><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important">-></span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">pid</span> . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">Swoole\Process</span>::<span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">wait</span>();</span>

新建外部 php 文件

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(86, 182, 194) !important"><?</span><span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(98, 151, 85) !important">// 24-exec.php</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(198, 120, 221) !important">echo</span> <span style="box-sizing: border-box;color: rgb(152, 195, 121) !important">'Swoole Process exec()'</span> . <span style="box-sizing: border-box;color: rgb(18, 170, 228) !important">PHP_EOL</span>;</span>

输出结果:

<span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(224, 108, 117) !important">$php</span> <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">24</span><span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">-swoole-process-base-exce</span>.php </span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">子进程 ID <span style="box-sizing: border-box;color: rgb(209, 154, 102) !important">75125</span></span><br></br><span style="box-sizing: border-box;color: rgb(171, 178, 191);padding-right: 0.1px">Swoole Process exec()</span>

本篇文章学习了 process 的基础使用,下篇文章继续学习 process。

请登录后再评论