Swoole从入门到入土(23)——多进程[进程池Process\Pool]
Swoole提供的进程池为Process\Pool,基于 Swoole\Server 的 Manager 管理进程模块实现。可管理多个工作进程。该模块的核心功能为进程管理,相比 Process 实现多进程,Process\Pool 更加简单,封装层次更高,开发者无需编写过多代码即可实现进程管理功能,配合 Co\Server 可以创建纯协程风格的,能利用多核 CPU 的服务端程序。同样,我们同过一段代码引出本节的详细讨论:
$workerNum = 10;
$pool = new Swoole\Process\Pool($workerNum); $pool->on("WorkerStart", function ($pool, $workerId) {
echo "Worker#{$workerId} is started\n";
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379);
$key = "key1";
while (true) {
$msg = $redis->brpop($key, 2);
if ( $msg == null) continue;
var_dump($msg);
}
}); $pool->on("WorkerStop", function ($pool, $workerId) {
echo "Worker#{$workerId} is stopped\n";
}); $pool->start();
现在让我们一起了解,这个类为我们提供了哪些成员。
常量

成员函数
1) __construct():构造方法
Swoole\Process\Pool::__construct(int $worker_num, int $ipc_type = 0, int $msgqueue_key = 0, bool $enable_coroutine = false);
$worker_num:工作进程的数量(当一个进程退出后,Pool会及时拉取另一个进程进行补充)
$ipc_type:进程间通信的模式【默认为 0 表示不使用任何进程间通信特性】,这个参数需要注意如下事项:
- 设置为 0 时必须设置 onWorkerStart 回调,并且必须在 onWorkerStart 中实现循环逻辑,当 onWorkerStart 函数退出时工作进程会立即退出,之后会由 Manager 进程重新拉起进程;
- 设置为 SWOOLE_IPC_MSGQUEUE 表示使用系统消息队列通信,可设置 $msgqueue_key 指定消息队列的 KEY,未设置消息队列 KEY,将申请私有队列;
- 设置为 SWOOLE_IPC_SOCKET 表示使用 Socket 进行通信,需要使用 listen 方法指定监听的地址和端口;
- 设置为 SWOOLE_IPC_UNIXSOCK 表示使用 unixSocket 进行通信,协程模式下使用,强烈推荐用此种方式进程间通讯;
- 使用非 0 设置时,必须设置 onMessage 回调,onWorkerStart 变更为可选。
$msgqueue_key:消息列队的key
$enable_coroutine:是否开启协程支持【使用协程后将无法设置 onMessage 回调】
示例1:
$pool = new Swoole\Process\Pool(1, SWOOLE_IPC_NONE, 0, true);
$pool->on('workerStart', function (Swoole\Process\Pool $pool, int $workerId) {
while (true) {
Co::sleep(0.5);
echo "hello world\n";
}
});
$pool->start();
示例2:开启协程后 Swoole 会禁止设置 onMessage 事件回调,需要进程间通讯的话需要将第二个设置为 SWOOLE_IPC_UNIXSOCK 表示使用 unixSocket 进行通信,然后使用 $pool->getProcess()->exportSocket() 导出 Coroutine\Socket 对象,实现 Worker 进程间通信。
$pool = new Swoole\Process\Pool(2, SWOOLE_IPC_UNIXSOCK, 0, true);
$pool->on('workerStart', function (Swoole\Process\Pool $pool, int $workerId) {
$process = $pool->getProcess(0);
$socket = $process->exportSocket();
if ($workerId == 0) {
echo $socket->recv();
$socket->send("hello proc1\n");
echo "proc0 stop\n";
} else {
$socket->send("hello proc0\n");
echo $socket->recv();
echo "proc1 stop\n";
$pool->shutdown();
}
});
$pool->start();
2) set():设置参数
Swoole\Process\Pool->set(array $settings)
可以使用 enable_coroutine 来控制是否启用协程,和构造函数的第四个参数作用一致。
Swoole\Process\Pool->set(['enable_coroutine' => true]);
3) on():设置进程池回调函数
Swoole\Process\Pool->on(string $event, callable $function);
$event:指定事件
$function:回调函数
事件说明:
- onWorkerStart:子进程启动,回调函数格式:
function onWorkerStart(Swoole\Process\Pool $pool, int $workerId) {
echo "Worker#{$workerId} is started\n";
}
- onWorkerStop:子进程结束,回调函数同onWorkerStart。
- onMessage:消息接收,收到外部投递的消息。 一次连接只能投递一次消息,类似于 PHP-FPM 的短连接机制。回调函数格式如下:
function onMessage(Swoole\Process\Pool $pool, string $data) {
var_dump($data);
}
4) listen():监听 SOCKET,必须在 $ipc_mode = SWOOLE_IPC_SOCKET 时才能使用。
Swoole\Process\Pool->listen(string $host, int $port = 0, int $backlog = 2048): bool
$host:监听的地址【支持 TCP 和 unixSocket 两种类型。127.0.0.1 表示监听 TCP 地址,需要指定 $port。unix:/tmp/php.sock 监听 unixSocket 地址。】
$port:监听的端口【在 TCP 模式下需要指定。】
$backlog:监听的队列长度
返回值:成功监听返回 true、监听失败返回 false,可调用 swoole_errno 获取错误码。监听失败后,调用 start 时会立即返回 false。
注意:向监听端口发送数据时,客户端必须在请求前增加 4 字节、网络字节序的长度值。协议格式为:packet = htonl(strlen(data)) + data;
示例:
$pool->listen('127.0.0.1', 8089);
$pool->listen('unix:/tmp/php.sock');
5) write():向对端写入数据,必须在 $ipc_mode 为 SWOOLE_IPC_SOCKET 时才能使用。
Swoole\Process\Pool->write(string $data): bool
$data:写入的数据内容【可多次调用 write,底层会在 onMessage 函数退出后将数据全部写入 socket 中,并 close 连接】
说明:此方法为内存操作,没有 IO 消耗,发送数据操作是同步阻塞 IO
示例:
/**** 服务端 ****/
$pool = new Swoole\Process\Pool(2, SWOOLE_IPC_SOCKET); $pool->on("Message", function ($pool, $message) {
echo "Message: {$message}\n";
$pool->write("hello ");
$pool->write("world ");
$pool->write("\n");
}); $pool->listen('127.0.0.1', 8089);
$pool->start(); /**** 客户端 ****/
$fp = stream_socket_client("tcp://127.0.0.1:8089", $errno, $errstr) or die("error: $errstr\n");
$msg = json_encode(['data' => 'hello', 'uid' => 1991]);
fwrite($fp, pack('N', strlen($msg)) . $msg);
sleep(1);
//将显示 hello world\n
$data = fread($fp, 8192);
var_dump(substr($data, 4, unpack('N', substr($data, 0, 4))[1]));
fclose($fp);
6) start():启动工作进程
Swoole\Process\Pool->start(): bool
说明1:
启动成功,当前进程进入 wait 状态,管理工作进程;
启动失败,返回 false,可使用 swoole_errno 获取错误码。
说明2:关于进程管理:
- 某个工作进程遇到致命错误、主动退出时管理器会进行回收,避免出现僵尸进程
- 工作进程退出后,管理器会自动拉起、创建一个新的工作进程
- 主进程收到 SIGTERM 信号时将停止 fork 新进程,并 kill 所有正在运行的工作进程
- 主进程收到 SIGUSR1 信号时将将逐个 kill 正在运行的工作进程,并重新启动新的工作进程
说明3:信号处理:
底层仅设置了主进程(管理进程)的信号处理,并未对 Worker 工作进程设置信号,需要开发者自行实现信号的监听。
- 工作进程为异步模式,请使用 Swoole\Process::signal 监听信号
- 工作进程为同步模式,请使用 pcntl_signal 和 pcntl_signal_dispatch 监听信号
在工作进程中应当监听 SIGTERM 信号,当主进程需要终止该进程时,会向此进程发送 SIGTERM 信号。如果工作进程未监听 SIGTERM 信号,底层会强行终止当前进程,造成部分逻辑丢失。
示例:
$pool->on("WorkerStart", function ($pool, $workerId) {
$running = true;
pcntl_signal(SIGTERM, function () use (&$running) {
$running = false;
});
echo "Worker#{$workerId} is started\n";
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379);
$key = "key1";
while ($running) {
$msg = $redis->brpop($key);
pcntl_signal_dispatch();
if ( $msg == null) continue;
var_dump($msg);
}
});
7) shutdown():终止工作进程
Swoole\Process\Pool->shutdown(): bool
8) getProcess():获取当前工作进程对象。返回 Swoole\Process 对象。
Swoole\Process\Pool->getProcess(int $worker_id): Swoole\Process;
$worker_id:指定获取 worker 【可选参数,默认当前 worker】
注意:
必须在 start 之后,在工作进程的 onWorkerStart 或其他回调函数中调用;
返回的 Process 对象是单例模式,在工作进程中重复调用 getProcess() 将返回同一个对象。
示例:
$workerNum = 10;
$pool = new Swoole\Process\Pool($workerNum); $pool->on("WorkerStart", function ($pool, $workerId) {
$process = $pool->getProcess();
$process->exec("/bin/sh", ["ls", '-l']);
}); $pool->on("WorkerStop", function ($pool, $workerId) {
echo "Worker#{$workerId} is stopped\n";
}); $pool->start();
Swoole提供的进程池成员简练,使用方便。以上就是进程池的所有内容,下一节我们将讨论进程管理器Manager:)
--------------------------- 我是可爱的分割线 ----------------------------
最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。
Swoole从入门到入土(23)——多进程[进程池Process\Pool]的更多相关文章
- day12学python 多进程+进程池
多进程+进程池 多进程(不同进程不可直接访问数据) 引入(多进程套线程) 多进程 需导入multiprocessing模块 模板示例1 import threading,time,multiproce ...
- Python进程池multiprocessing.Pool的用法
一.multiprocessing模块 multiprocessing模块提供了一个Process类来代表一个进程对象,multiprocessing模块像线程一样管理进程,这个是multiproce ...
- 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型
进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...
- Python多进程-进程池
进程池可以减轻多进程对CPU的负担 把一个进程序列放入进程池,使用的时候,就会在进程池中取进程如果进程池中没有进程了,脚本就会等待,直到进程池中有可用进程 进程池生成的子线程,不能直接运行,要放入进程 ...
- python3多进程 进程池 协程并发
一.进程 我们电脑的应用程序,都是进程,进程是资源分配的单位.进程切换需要的资源最大,效率低. 进程之间相互独立 cpu密集的时候适合用多进程 #多 ...
- Python 多进程进程池Queue进程通信
from multiprocessing import Pool,Manager import time def hanshu(queue,a): n = 1 while n<50: # pri ...
- python进程池multiprocessing.Pool和线程池multiprocessing.dummy.Pool实例
进程池: 进程池的使用有四种方式:apply_async.apply.map_async.map.其中apply_async和map_async是异步的,也就是启动进程函数之后会继续执行后续的代码不用 ...
- Python程序中的进程操作-进程池(multiprocess.Pool)
目录 一.进程池 二.概念介绍--multiprocess.Pool 三.参数用法 四.主要方法 五.其他方法(了解) 六.代码实例--multiprocess.Pool 6.1 同步 6.2 异步 ...
- python中的进程池:multiprocessing.Pool()
python中的进程池: 我们可以写出自己希望进程帮助我们完成的任务,然后把任务批量交给进程池 进程池帮助我们创建进程完成任务,不需要我们管理.进程池:利用multiprocessing 下的Pool ...
- 【python小随笔】进程池 multiprocessing.Pool的简单实现与踩过的坑
#导入进程模块 import multiprocessing #创建进程池 坑:一定要在循环外面创建进程池,不然会一直创建 pool = multiprocessing.Pool(30) for Si ...
随机推荐
- Python学习之十六_virsh批量获取虚拟机IP地址的方法
Python学习之十六_virsh批量获取虚拟机IP地址的方法 Linux命令说明 for j in \ $(for i in `virsh list |grep -v Id |grep runnin ...
- [转帖]windows10彻底关闭Windows Defender的4种方法
https://zhuanlan.zhihu.com/p/495107049 Windows Defender是windows10系统自带的杀毒软件.默认情况下它处于打开的状态.大多数第三方的杀毒软件 ...
- Oracle session的sid与serial的简单学习
Oracle session的sid与serial的简单学习 ITPUB vage的说法 这样说吧,Oracle允许的会话数(或者说连接数)是固定的,比如是3000个.假设每个会话要占1K字节,哪一共 ...
- [转帖]配置ftp连接对象存储bucket子目录的方法
https://developer.jdcloud.com/article/1838 配置ftp连接对象存储bucket子目录的方法 京东云技术交付部 2021-01-27 IP归属:未知 441 ...
- [转帖]将 Cloudflare 连接到互联网的代理——Pingora 的构建方式
https://zhuanlan.zhihu.com/p/575228941 简介 今天,我们很高兴有机会在此介绍 Pingora,这是我们使用 Rust 在内部构建的新 HTTP 代理,它每天处理超 ...
- [转帖]iozone磁盘读写测试工具的使用以及命令详解、下载(网站最详细讲解步骤)
一.iozone简介 iozone是一款开源工具,用来测试文件系统的读写性能,也可以进行测试磁盘读写性能. 二.下载 方式一:网站下载http://www.iozone.org/ 方式二:个人网盘存放 ...
- [转帖]一口气看完45个寄存器,CPU核心技术大揭秘
https://www.cnblogs.com/xuanyuan/p/13850548.html 序言 前段时间,我连续写了十来篇CPU底层系列技术故事文章,有不少读者私信我让我写一下CPU的寄存器. ...
- Cosmic云星瀚的简单学习-测试用户创建
摘要 上一个学习文档里面总结了: 修改domain的url之后就可以重启服务然后登录了. 今天中午创建了一个业务用户,发现还挺麻烦的 因为可能短信服务有问题, 所以我这边需要有改数据库表的需求. 这里 ...
- 【VictoriaMetrics源码阅读】vm中仿照RoaringBitmap的实现:uint64set
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu 公众号:一本正经的瞎扯 正文 VictoriaMetrics中使用uint64类型来表示一个Me ...
- Python 潮流周刊第 37 期(摘要)
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...