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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ParameterizedThreadStart 实例化[通俗易懂]

    ParameterizedThreadStart 实例化[通俗易懂]C#之线程ParameterizedThreadStart今天用到了ParameterizedThreadStart的实例化对象,但是总提示没有与委托匹配的重载,网上搜索了很多,终于明白什么原因了,再次记录下方便以后查阅。classProgram{staticvoidMain(string[]args){Workwork=newWork();//两种实…

    2022年7月15日
    17
  • 51单片机设计8位抢答器_51单片机八路抢答器原理图

    51单片机设计8位抢答器_51单片机八路抢答器原理图基于51单片机八路抢答器的设计毕业设计(论文)题目:基于51单片机八路抢答器的设计系部:专业:学号:学生姓名:指导教师姓名:指导教师职称:2013年xx月xx日XXXXXXXX学院(论文)I摘要随着科学技术的发展和普及,各种各样的竞赛越来越多,其中抢答器的作用也就显而易见。目前很多抢答器基本上采用小规模数字集成电路设计,使用起来不够理想。因此设计一更易于使…

    2022年10月20日
    3
  • pytest重试_联系人去重失败

    pytest重试_联系人去重失败安装:pip3installpytest-rerunfailures重新运行所有失败用例要重新运行所有测试失败的用例,请使用–reruns命令行选项,并指定要运行测试的最大次数:$py

    2022年7月31日
    5
  • REST API和SOAP API之间的区别

    REST API和SOAP API之间的区别TheRepresentationalStateTransfer(REST)架构风格不是可以购买的技术,也不是可以添加到软件开发项目中的库。REST是一种世界观,将信息提升为我们构建的体系结构的第一流元素。RoyFielding博士的论文“架构风格和基于网络的软件架构设计”介绍并整理了用于描述“RESTful”系统的思想和术语。这是一份学术文件,但通过提供RESTful架构的基础,可…

    2022年7月13日
    16
  • C#单纯的字母数字ASCII码转换

    字母转换成数字byte[]array=newbyte[1];//定义一组数组arrayarray=System.Text.Encoding.ASCII.GetBytes(string

    2021年12月27日
    44
  • Android Activity为什么要细化出onCreate、onStart、onResume、onPause、onStop、onDesdroy这么多方法让应用去重载?

    Android Activity为什么要细化出onCreate、onStart、onResume、onPause、onStop、onDesdroy这么多方法让应用去重载?最近在研究Activity的启动流程,老罗的blog在看,也找了其它资料学习,也跟过Android4.3的源码,在跟代码的过程中,突然想到下面的这个问题:  AndroidActivity为什么要细化出onCreate、onStart、onResume、onPause、onStop、onDesdroy这么多方法让应用去重载?网上太多根据Android开发规范翻译转载的内容,都不是我想要的答案,那就自己分析下

    2022年5月5日
    37

发表回复

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

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