Swoole的多进程模块[通俗易懂]

Swoole的多进程模块

大家好,又见面了,我是全栈君。

点击上方“码农编程进阶笔记”,选择“置顶或者星标

优质文章第一时间送达

Swoole是有自己的一个进程管理模块,用来替代PHP的pcntl扩展,需要注意Process进程在系统是非常昂贵的资源,创建进程消耗很大,另外创建的进程过多会导致进程切换开销大幅上升。

为什么不使用pcntl

1.pcntl没有提供进程间通信的功能

2.pcntl不支持重定向标准输入和输出

3.pcntl只提供了fork这样原始的接口,容易使用错误

Swoole是怎么解决的

1.swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可

 2.swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据

 3.swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信

创建进程

函数原型:

Swoole\Process::__construct(callable $function, $redirect_stdin_stdout = false, $create_pipe = true)

1.$function,子进程创建成功后要执行的函数,底层会自动将函数保存到对象的callback属性上。如果希望更改执行的函数,可赋值新的函数到对象的callback属性

2.$redirect_stdin_stdout,重定向子进程的标准输入和输出。启用此选项后,在子进程内输出内容将不是打印屏幕,而是写入到主进程管道。读取键盘输入将变为从管道中读取数据。默认为阻塞读取。

3.$create_pipe,是否创建管道,启用$redirect_stdin_stdout后,此选项将忽略用户参数,强制为true。如果子进程内没有进程间通信,可以设置为 false。

swoole创建多进程很简单:
new Swoole\Process('callback_function') 就可以了,比如我要同时创建6个进程,就for 循环6次就可以了。

假设前台给后台三组任务要求后台去执行,每个任务大概需要执行一秒的时间,我们利用多进程的形式去实现,让时间能够缩短。

for ($i = 0; $i < 6; $i++) {#创建了3个子进程
    $process = new Swoole\Process(function ($process) {
        sleep(1);
        echo PHP_EOL . posix_getpid() . PHP_EOL;#获取子进程PID
    }, false, true);
    $process->start();

进程间的通讯

如果是非常简单的多进程执行任务,那么进程间就不需要通讯了,实际情况下,很多业务是需要通讯的,比如,发邮件,如果自进程发送失败了,那么是要通知主进程的等等。

swoole_process进程间支持2种通信方式:

1.管道pipe

2.消息队列

管道通讯

半双工: 数据单向流动, 一端只读, 一端只写。
同步 vs 异步: 默认为同步阻塞模式, 可以使用 swoole_event_add() 添加管道到 swoole 的 event loop 中, 实现异步IO

Swoole的多进程模块[通俗易懂]

管道通信是swoole_process默认的一种通信方式。当然我们也可以在实例化的时候通过参数来设定:

$process = new Swoole\Process('callback_function', false, true);

如果我们打印$process会发现,每次创建一个进程后,就会随之创建一个管道,主进程想和哪一个进程通信,就向那个进程的管道写入/读取数据。

管道有2个方法,分别来写入数据,和读取数据。

  1. $process->write(‘数据’);#写入数据

  2. $process->read()#读取数据

管道通讯方式一:

$worker = [];
for ($i = 0; $i < 3; $i++) {
    $process = new Swoole\Process(function ($process) {
        var_dump('子进程:' . $process->read());
        sleep(1);
        $process->write('子进程数据');
        echo PHP_EOL . posix_getpid() . PHP_EOL;
    }, false, true);
    $pid = $process->start();
    $worker[$pid] = $process;//把相应的进程放到同一个数组当中
    $process->write('主进程数据');
//    var_dump($process->read());//同步阻塞
}
foreach ($worker as $w) {
    var_dump('主进程:' . $w->read());
}

管道通讯方式二:

for ($i = 0; $i < 3; $i++) {
    $process = new Swoole\Process(function ($process) {
        var_dump('子进程:' . $process->read());
        sleep(1);
        $process->write('子进程数据');
        echo PHP_EOL . posix_getpid() . PHP_EOL;
    }, false, true);
    $pid = $process->start();
    $process->write('主进程数据');
    // 异步监听管道中的数据,读事件监听,当管道可读时触发
    swoole_event_add($process->pipe, function ($pipe) use ($process) {
        var_dump('主进程:' . $process->read());
    });
//    var_dump($process->read());//同步阻塞
}

消息队列的通讯

消息队列:

  1. 一系列保存在内核中的消息链表

  2. 有一个 msgKey, 可以通过此访问不同的消息队列

  3. 有数据大小限制, 默认 8192

  4. 阻塞 vs 非阻塞: 阻塞模式下 pop()空消息队列/push()满消息队列会阻塞, 非阻塞模式可以直接返回

swoole 中使用消息队列:

  1. 通信模式: 默认为争抢模式, 无法将消息投递给指定子进程

  2. 新建消息队列后, 主进程就可以使用

  3. 消息队列不可和管道一起使用, 也无法使用 swoole     event loop

步骤:

1.启用消息队列作为进程间通信:

bool swoole_process->useQueue(int $msgkey = 0, int $mode = 2);

2.投递数据到消息队列中:

 bool swoole_process->push(string $data);

3.从队列中提取数据

string swoole_process->pop(int $maxsize = 8192);

案例:

for ($i = 0; $i < 3; $i++) {
    $process = new Swoole\Process(function ($process) {
        var_dump('子进程:' . $process->pop());
//        $process->push('hello 主进程');#推送到主进程
    });
    $process->useQueue(1, 2 | swoole_process::IPC_NOWAIT);//启用消息队列,争抢模式,非阻塞,可能会被任意一个子进程接收到
    $pid = $process->start();


    $process->push('hello 子进程');#推送到子进程,不能当做管道使用
//    echo '主进程消息:' . $process->pop() . PHP_EOL;
}

如果你对这篇文章感兴趣,帮忙一下或者点击文章右下角在。感谢啦!关注公众号,回复「进群」即可进入无广告技术交流群

Swoole的多进程模块[通俗易懂]

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/112027.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 无锁队列实现原理_优先队列 java

    无锁队列实现原理_优先队列 java首次接触无锁数据结构的设计,请各位大佬多多指教~~~CAS(Compare&&Swap)原子操作CAS是无锁(lockfree)的数据结构的基础。用伪代码描述:input:reg,old_val,new_val/*是old_val,reg替换为new_val,返回为true;否则返回为false*/if(*reg==old_val){*reg==new…

    2025年8月25日
    4
  • linux目录结构详解_linux目录的结构及含义

    linux目录结构详解_linux目录的结构及含义前言平常linux系统用的也不少,那么linux下的每个目录都是用来干什么的,小伙伴们有仔细研究过吗?让我们来了解下吧Linux系统目录结构登录系统后,在当前命令窗口下输入命令:[root@

    2022年7月31日
    6
  • JAVA中读写文件操作

    JAVA中读写文件操作java文件读取有两种类型,我这里的是字节流的读取操作packagetest1;importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importja…

    2022年7月14日
    15
  • Postman使用教程图解

    Postman使用教程图解postman的主要功能1、模拟HTTPrequests的一些方法:get、post、put等2、Collection:测试集合,你每测试一个项目建立一个collection,把请求放在一起,方便日后查阅,而且还能Import或者Share,整个团队的人都可以看到;3、Response形式多样一般在用其他工具来测试的時候,response的内容通常都是纯文字的raw,但如果是JSON,就是塞成一整行的JSON。这会造成阅读的障碍,而Postman可以针对response

    2022年5月31日
    50
  • pytorch转tensorflow_语义分割样本不均衡

    pytorch转tensorflow_语义分割样本不均衡憨批的语义分割重制版7——TF2搭建自己的Unet语义分割平台注意事项学习前言什么是Unet模型代码下载Unet实现思路一、预测部分1、主干网络介绍2、加强特征提取结构3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS解析训练自己的Unet模型注意事项这是重新构建了的Unet语义分割网络,主要是文件框架上的构建,还有代码的实现,和之前的语义分割网络相比,更加完整也更清晰一些。建议还是学习这个版本的Unet。学习前言还是快乐的pytorch人。什么是Unet模型Unet是一个优秀

    2022年8月21日
    9
  • 宿主机和虚拟机的网络_vmware独享宿主机网卡

    宿主机和虚拟机的网络_vmware独享宿主机网卡问题描述:宿主机为win10家庭版,虚拟机为Centos7,上午还可以正常的进行互通,中间应该是弹出来一个外设的接入通知,其他的没有什么明显的操作,下午就不能互相访问了,原因不明。解决方法:首先检查虚拟机的网络配置,分为如下几步:1、编辑–>虚拟机网络编辑器,选择桥接模式,同时选择要桥接的网络:这个网路需要和宿主机中的网络保持一致,如果宿主机中存在多个网络连接,比如无线连接和有线连接,那就根据实际需要,看虚拟机需要连接到哪个网络中,就对应选择。选择完之后,确

    2022年8月21日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号