Skip to content

老陈是一个普通的文艺二逼青年

For The Dream

swoole —— process

Written by chen
  • 创建进程
  • 进程间通信
    • 管道
    • 队列
    • 信号
  • 其他
    • 执行系统命令
    • 回收
    • 守护进程
    • 命名进程
    • CPU亲和性

swoole_process

swoole的进程对比pcntl扩展进程的优势:

  • pcntl无法用在fpm/apache中
  • pcntl没有提供进程间通信的功能
  • pcntl不支持重定向标准输入和输出
  • pcntl只提供了fork这样原始的接口,容易使用错误
  • swoole_process提供了比pcntl更强大的功能,更易用的API,使PHP在多进程编程方面更加轻松。

创建进程

原型:

1
2
int swoole_process::__construct(mixed $function, $redirect_stdin_stdout = false, $create_pipe = true);
 

参数:

  • function: 子进程创建成功后要执行的函数
  • redirect_stdin_stdout: 重定向子进程的标准输入和输出。 启用此选项后,在进程内echo将不是打印屏幕,而是写入到管道。读取键盘输入将变为从管道中读取数据。 默认为阻塞读取。
  • create_pipe: 是否创建管道,启用redirect_stdin_stdout后,此选项将忽略用户参数,强制为true 如果子进程内没有进程间通信,可以设置为false

返回值:

swoole_process对象,数据结构包括了管道描述符和回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$process = new swoole_process(function (swoole_process $worker) {
    echo "process: echo 1";
    print_r($worker);
});
 
$pid = $process -> start();
 
echo "pid:", $pid, "\n";
 
/*
pid:12057
process: echo 1
swoole_process Object
(
    [pipe] => 4
    [callback] => Closure Object
        (
            [parameter] => Array
                (
                    [$worker] => <required>
                )
 
        )
 
    [pid] => 12167
)
 
*/
 
 

进程间通信

管道

当创建进程时,进行了输入输出重定向,swoole就会帮我们自动创建管道。

1
2
3
4
5
6
7
8
9
10
11
$process = new swoole_process(function (swoole_process $worker) {
    echo "process: echo 1";
}, true);
 
$pid = $process -> start();
 
echo "pid:", $pid, "\n";
/*
pid:12057
*/
 

这里运行程序并不会输出process: echo 1。因为输出意见被输入到管道中去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$process = new swoole_process(function (swoole_process $worker) {
    echo "process: echo 1";
}, true);
 
$pid = $process -> start();
 
echo "pid:", $pid, "\n";
 
echo $process -> read();
/*
pid:12057
process_1.php
*/
 

这里我们关闭输出输入重定向,并且开启管道。进行一个简单的案例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$process = new swoole_process(function (swoole_process $worker) {
    echo $worker -> read(), "\n";
    $worker -> write("hello parent, I'm child #" . $worker->pid);
    $worker -> exit(0);
}, false, true);
 
$pid = $process -> start();
 
$process -> write("hello, child #".$pid.",  I'm parent");
 
echo $process -> read(), "\n";
 
/*
hello, child #12197,  I'm parent
hello parent, I'm child #12197
*/
 

队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$process = new swoole_process(function (swoole_process $worker) {
    echo $worker -> pop(), "\n";
    $worker -> push("hello parent, i'm child #".$worker->pid);
    $worker->exit(0);
}, false);
$process->useQueue();
$pid = $process->start();
 
$process->push("hello child #{$pid}, i'm parent");
echo $process -> pop(), "\n";
$ret = swoole_process::wait();
print_r($ret);
/*
hello child #23747, i'm parent
hello parent, i'm child #23747
Array
(
    [code] => 0
    [pid] => 23749
    [signal] => 0
)
*/
 

信号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$process = new swoole_process(function (swoole_process $worker) {
 
    /**
     * 注册信号
     * 当前进程被kill触发
     */
    swoole_process::signal(SIGTERM, function($signal_num) use ($worker) {
        echo "signal SIGTERM call = $signal_num, #{$worker -> pid}\n";
 
        // todo something
 
        $worker -> exit(0);
    });
 
    for ($i=0; $i < 100000000; $i++) { }
}, false);
 
/**
* 注册信号
* 子进程被kill触发
*/
swoole_process::signal(SIGCHLD, function($signal_num) use ($process) {
    echo "signal SIGCHLD call = $signal_num, #{$process -> pid}\n";
 
    /**
     * 回收子进程
     */
    while($ret =  swoole_process::wait(false)) {
        echo "PID={$ret['pid']}\n";
    }
});
 
$pid = $process->start();
 
swoole_process::kill($pid); # kill 子进程
 
 

父进程中注册信号(子进程被kill触发),自进程中注册信号(本身被kill触发)。

开启子进程后,父进程立即杀死子进程,触发子进程信号事件。子进程关闭后,触发父进程信号事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 信号类型列表
 
编号  信号名称    缺省动作    说明
1   SIGHUP  终止  终止控制终端或进程
2   SIGINT  终止  键盘产生的中断(Ctrl-C)
3   SIGQUIT dump    键盘产生的退出
4   SIGILL  dump    非法指令
5   SIGTRAP dump    debug中断
6   SIGABRT/SIGIOT  dump    异常中止
7   SIGBUS/SIGEMT   dump    总线异常/EMT指令
8   SIGFPE  dump    浮点运算溢出
9   SIGKILL 终止  强制进程终止
10  SIGUSR1 终止  用户信号,进程可自定义用途
11  SIGSEGV dump    非法内存地址引用
12  SIGUSR2 终止  用户信号,进程可自定义用途
13  SIGPIPE 终止  向某个没有读取的管道中写入数据
14  SIGALRM 终止  时钟中断(闹钟)
15  SIGTERM 终止  进程终止
16  SIGSTKFLT   终止  协处理器栈错误
17  SIGCHLD 忽略  子进程退出或中断
18  SIGCONT 继续  如进程停止状态则开始运行
19  SIGSTOP 停止  停止进程运行
20  SIGSTP  停止  键盘产生的停止
21  SIGTTIN 停止  后台进程请求输入
22  SIGTTOU 停止  后台进程请求输出
23  SIGURG  忽略  socket发生紧急情况
24  SIGXCPU dump    CPU时间限制被打破
25  SIGXFSZ dump    文件大小限制被打破
26  SIGVTALRM   终止  虚拟定时时钟
27  SIGPROF 终止  profile timer clock
28  SIGWINCH    忽略  窗口尺寸调整
29  SIGIO/SIGPOLL   终止  I/O可用
30  SIGPWR  终止  电源异常
31  SIGSYS/SYSUNUSED    dump    系统调用异常
 

其他

执行系统命令

1
2
3
4
5
6
7
8
9
10
$process = new swoole_process(function (swoole_process $worker) {
 
    $worker -> exec('/bin/ps', ['-ef']);
 
}, false);
 
$pid = $process->start();
 
swoole_process::wait();
 

会输出 ps -ef执行后内容。

回收

子进程结束必须要执行wait进行回收,否则子进程会变成僵尸进程

守护进程

使当前进程脱变为一个守护进程。

1
2
3
4
5
6
7
swoole_process::daemon();
 
while (true) {
    echo "hello";
    sleep(1);
}
 

命名进程

1
2
3
4
5
6
7
8
9
10
11
12
$process = new swoole_process(function (swoole_process $worker) {
 
    $worker -> name('child_namne_process_#' . $worker->pid);
 
    sleep(10);
 
}, false);
 
$pid = $process->start();
 
swoole_process::wait();
 

1
2
3
4
5
6
ps -ef
 
root     24211 11981  0 16:48 pts/2    00:00:00 php process_name.php
root     24212 24211  0 16:48 pts/2    00:00:00 child_namne_process_#24212
 
 

CPU亲和性

设置CPU亲和性,可以将进程绑定到特定的CPU核上。

PHP · php, swoole, 多进程

Copyright © 2022 老陈是一个普通的文艺二逼青年. 沪ICP备13044041号-1