php多进程

    前不久写了一个简单的不用php redis扩展的redis队列(原理是socket和redis的通讯协议RESP),里面有个开始队列的函数,执行的是rpop存储在redis的列表数据。想优化一下这里的代码,不是一个一个地rpop,而是开启多个进程执行rpop。多线程和多进程的概念不再描述了,多进程可以了解一下php-fpm(FastCGI进程管理器),但是这里也不是用这个;据我了解,php是没有多线程这个概念的.....刚开始我都不知道php可以是多进程的呢。

    pcntl_fork(),就是fork一个子进程,fork后面的代码个人理解是拷贝了两份一样的代码执行。fork>0返回子进程的pid是主进程,0的话是子进程,不是完美主义者(什么主进程没加pcntl_wait,子进程会变成僵尸进程),也不是想细说什么技术道理(你怎么不讲fork什么原理),这些稍微理解一下但又理解不透彻的东西,就不讨论了,只是探讨我发现的一些问题。

public function start(){
    $fork = pcntl_fork();
    if ($fork < 0) {
        var_dump('fork 子进程失败');
    } elseif ($fork) {
        //父进程
        var_dump('父进程开始任务');
        $this->pop();
        var_dump('父进程完成任务,sleep 2秒');
        sleep(2);
    } else {
        // 子进程
        var_dump('子进程开始任务');
        $this->pop();
        var_dump('子进程完成任务,sleep 2秒');
        sleep(2);
    }
}

    多次运行后,并不是我想要的结果,输出的数据有时还会叠在一起。考虑到的情况是redis两次返回的结果被同一个fread读取到了。

    这不好办吗,子进程或者主进程稍微sleep一下就好啦

public function start(){
    $fork = pcntl_fork();
    if ($fork < 0) {
        var_dump('fork 子进程失败');
    } elseif ($fork) {
        //父进程
        var_dump('父进程开始任务');
        $this->pop();
        var_dump('父进程完成任务,sleep 1秒');
        sleep(1);
    } else {
        // 子进程
        usleep(100);//稍微sleep一下
        var_dump('子进程开始任务');
        $this->pop();
        var_dump('子进程完成任务,sleep 2秒');
        sleep(2);
    }
}

    稍微sleep一下的话,出现重叠的概率少了,但是redis那边read的时候还是会重叠,到现在都没有解决这个问题。仔细想想的话,这里100个同时请求redis里的数据,redis还不是要一个一个地执行?还不如一次性取所有的数据(redis的管道),所以突然放弃研究这个问题了。然后想到另外一个问题,如果我要先执行子进程再执行父进程要怎么控制呢?又涉及到进程间的通讯。

    进程间如何通讯这个也不细说了,信号,管道,共享内存,消息队列网上搜一下很多。我这里只是想讨论如何控制父子进程的执行顺序,我想到的是用管道,stream_socket_pari(),管道0写入数据,管道1读取数据,一个进程fread管道1阻塞等待另一个进程向管道0fwrite写入数据。

<?php
$socket = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);

if (!$socket) {
    var_dump('stream_socket_pair创建失败');
}

$file = './text.txt';
$fp = fopen($file, 'a');

$fork = pcntl_fork();

if ($fork < 0) {
    var_dump('fork失败');
} elseif ($fork) {
    //父进程
    for($i=0;$i<50;$i++) {
        fwrite($fp, 'a');
    }
    fwrite($socket[0], 'ok');
    fclose($fp);
    fclose($socket[1]);
    fclose($socket[0]);
} else {
    //子进程
    fread($socket[1], 215);
    for($i=0;$i<50;$i++) {
        fwrite($fp, 'b');
    }
    fclose($socket[1]);
    fclose($socket[0]);
    fclose($fp);
}

    该代码的逻辑就是fork两个进程,一个进程写入a,写完后另一个进程写入b。聪明的你应该已经知道如果要顺序执行的话,为什么要fork两个进程?是的,这两个例子我都觉得多此一举,但是这些是我亲自实践后才知道这样为什么不行,而且说不定这种思想以后会用到别的地方,最重要的是这过程中学到更多的之前不懂的知识,还有引出一个很重要的东西,socket,几乎哪里都能用到socket,接下来就是要研究这个东西了。

  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

roxasu

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值