PHP多进程初步

一、前言

我们都知道PHP是单线程执行,处理多并发主要是依赖服务器或PHP-FPM的多进程及它们进程的复用,但PHP实现多进程也意义重大,尤其是在后台Cli模式下处理大量数据或运行后台DEMON守护进程时。不能应用在Web服务器环境。

/** 检测是否CLI模式,确保这个函数只能运行在SHELL中 */
if (substr(php_sapi_name(), 0, 3) !== ‘cli‘) {
  die("cli mode only");
}

日常任务中,有时需要通过php脚本执行一些日志分析,队列处理等任务,当数据量比较大时,可以使用多进程来处理。

PHP的多线程也曾被人提及,但进程内多线程资源共享和分配的问题难以解决。PHP也有多线程想关的扩展 pthreads ,但据说不太稳定,且要求环境为线程安全,所用不多。

要实现PHP的多进程,需要安装 pcntl 和 posix 扩展。

二、创建子进程

使用 pcntl_fork() 函数可以在当前位置产生分支。fork 是创建了一个子进程,父进程和子进程都从 fork 的位置开始向下继续执行,不同的是父进程执行过程中,得到的 fork 返回值为子进程号,而子进程得到的是0,执行失败则返回-1。

因为系统初始init进程的pid为1,后来的所有进程pid都会大于该进程,所以可以通过 pcntl_fork() 的返回值大于1来判断当前进程是父进程,返回值等于0来判断是子进程。

$ppid = posix_getpid(); // 获取当前进程的id
$pid = pcntl_fork();  // 创建子进程
if ($pid == -1) {
    throw new Exception(‘fork子进程失败!‘);
} elseif ($pid > 0) {
    // 父进程执行逻辑
    cli_set_process_title("我是父进程,我的进程id是{$ppid}.");
    sleep(30);
    pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
    // 子进程执行逻辑
    $cpid = posix_getpid();
    cli_set_process_title("我是{$ppid}的子进程,我的进程id是{$cpid}.");
    sleep(30);
}

执行结果:

注意:如果是在循环中创建子进程,那么子进程中最后要 exit 退出,防止子进程进入循环。

三、管理子进程

管理子进程,使用的是信号。简单来说,就是父进程里使用两个函数 pcntl_signal() 和 pcntl_signal_dispatch(),负责给子进程安装信号处理器和分发工作。

在计算机科学中,信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。

我们通过在父进程接收子进程传来的信号,判断子进程状态,来对子进程进行管理。我们需要在父进程里使用 pcntl_signal() 函数和 pcntl_signal_dispatch() 函数来给各个子进程安装信号处理器:

// 安装一个信号处理器,$signo是待处理的信号常量,callback是其处理函数
pcntl_signal (int $signo , callback $handler)
// 调用每个等待信号通过pcntl_signal()安装的处理器
pcntl_signal_dispatch () 

PHP内常见的信号常量有:

  • SIGCHLD:子进程退出成为僵尸进程会向父进程发送此信号
  • SIGHUP:进程挂起
  • SIGTEM:进程终止

四、处理子进程

处理子进程,需要两个函数:

// 向进程id为$pid的进程发送$sig信号
bool posix_kill ( int $pid, int $sig )
//挂起当前进程的执行直到进程号为$pid的进程退出(如果$pid为-1,则等待任意一个子进程)
int pcntl_waitpid ( int $pid, int &$status [, int $options = 0 ] )

posix_kill() 函数通过向子进程发送一个信号来操作子进程,在需要要时可以选择给子进程发送进程终止信号来终止子进程;

pcntl_waitpid() 函数等待或返回 fork 的子进程状态,如果指定的子进程在此函数调用时已经退出(俗称僵尸进程),此函数将立刻返回,并释放子进程的所有系统资源,此进程可以避免子进程变成僵尸进程,造成系统资源浪费。这样就可以实现跟子进程共同完成的任务的目的了。

五、实例

如果一个任务被分解成多个进程执行,就会减少整体的耗时。比如有一个比较大的数据文件要处理,这个文件由很多行组成。如果单进程执行要处理的任务,量很大时要耗时比较久。这时可以考虑多进程。多进程处理分解任务,每个进程处理文件的一部分,这样需要均分割一下这个大文件成多个小文件(进程数和小文件的个数等同就可以)。

比如文件 file.log 有10万行数据,现在想分4个进程处理。需要分割2.5万行一个文件。命令 split 可以做到:

<?php

shell_exec(‘split -l 25000 -d file.log prefix_name‘);

// 3个子进程处理任务
for ($i = 0; $i < 3; $i++){
    $pid = pcntl_fork();

    if ($pid == -1) {
        die("could not fork");
    } elseif ($pid) {
        echo "I‘m the Parent $i\n";
    } else {// 子进程处理
        $content = file_get_contents("prefix_name0".$i);
        // 业务处理 begin

        // 业务处理 end
        exit; // 一定要注意退出子进程,否则pcntl_fork()会被子进程再fork,带来处理上的影响。
    }
}

// 等待子进程执行结束
while (pcntl_waitpid(0, $status) != -1) {
    $status = pcntl_wexitstatus($status);
    echo "Child $status completed\n";
}

参考:

《php多进程总结》:https://www.cnblogs.com/leezhxing/p/5223289.html

《初探PHP多进程》:https://www.cnblogs.com/zhenbianshu/p/5676822.html

《PHP利用多进程处理任务》:https://www.cnblogs.com/firstForEver/p/7301630.html

原文地址:https://www.cnblogs.com/tangxuliang/p/9208133.html

时间: 2024-10-12 13:07:27

PHP多进程初步的相关文章

Python标准库10 多进程初步 (multiprocessing包)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们已经见过了使用subprocess包来创建子进程,但这个包有两个很大的局限性:1) 我们总是让subprocess运行外部的程序,而不是运行一个Python脚本内部编写的函数.2) 进程间只通过管道进行文本交流.以上限制了我们将subprocess包应用到更广泛的多进程任务.(这样的比较实际是不公平的,因为subprocessing本身就是设计成为一个shell,而不是一个多

Python标准库11 多进程探索 (multiprocessing包)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在初步了解Python多进程之后,我们可以继续探索multiprocessing包中更加高级的工具.这些工具可以让我们更加便利地实现多进程. 进程池 进程池 (Process Pool)可以创建多个进程.这些进程就像是随时待命的士兵,准备执行任务(程序).一个进程池中可以容纳多个待命的士兵. "三个进程的进程池" 比如下面的程序: import multiprocess

Python的多线程与多进程实践

最近要产生大量的”假“的电话号码,所以就写了一个自动产生电话号码程序,产生了一百万条数据,然后把数据放到一个文件中. 死跑版: # -*- coding: utf-8 -*- # 以下是中国的手机号码分段情况 # 新联通 (中国联通+中国网通)手机号码开头数字 130.131.132.145. # 155.156.185.186 # 新移动 (中国移动+中国铁通)手机号码开头数字 134.135.136.137. # 138.139.147.150.151.152.157.158.159.182

Python快速教程

Python快速教程 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 怎么能快速地掌握Python?这是和朋友闲聊时谈起的问题. Python包含的内容很多,加上各种标准库.拓展库,乱花渐欲迷人眼.我一直希望写一个快速的.容易上手的Python教程,而且言语简洁,循序渐进,让没有背景的读者也可以从基础开始学习.我将在每一篇中专注于一个小的概念,希望在闲暇时可以很快读完. 小提醒 教程将专注于Python基础,语法基于Pytho

Python系列教程大汇总

Python初级教程 Python快速教程 (手册) Python基础01 Hello World! Python基础02 基本数据类型 Python基础03 序列 Python基础04 运算 Python基础05 缩进和选择 Python基础06 循环 Python基础07 函数 Python基础08 面向对象的基本概念 Python基础09 面向对象的进一步拓展 Python基础10 反过头来看看 Python补充01 序列的方法 Python中级教程 Python进阶01 词典 Pytho

Python应用01 原始Python服务器

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 之前我的Python教程中有人留言,表示只学Python没有用,必须学会一个框架(比如Django和web.py)才能找到工作.而我的想法是,掌握一个类似于框架的高级工具是有用的,但是基础的东西可以让你永远不被淘汰.不要被工具限制了自己的发展.今天,我在这里想要展示的,就是不使用框架,甚至不使用Python标准库中的高级包,只使用标准库中的socket接口(我不是很明白套接字这个

Python 学习入门(0)—— 简明教程

朋友问我怎么能快速地掌握Python. 我想Python包含的内容很多,加上各种标准库,拓展库,乱花渐欲迷人眼,就想写一个快速的Python教程,一方面 保持言语的简洁,另一方面循序渐进,尽量让没有背景的读者也可以从基础开始学习.另外,我在每一篇中专注于一个小的概念,希望可以让人可以在闲暇时很快读完. 小提醒 1. 教程将专注于Python基础,语法基于Python 2.7,测试环境为Linux, 不会使用到标准库之外的模块. 2. 我将专注于Python的主干,以便读者能以最快时间对Pytho

项目分析(多进程数据走向初步)

1.数据的来源 NetProcSvr::init()->libevent::conn_readcb(读事件)->Channel::read_datastream(读到数据流)->TCPServer::on_receive_data读包->from_net_push_pkt(放到无锁队列中去即m_all_packet) 2.初步处理 线程函数(fromNet2Mem)->TCPServer::recv(从无锁队列中取包)->m_spShareMemInter::pushA

PHP多进程编程初步

转自:https://www.pureweber.com/article/php-multi-process-programming-preview/ 羡慕火影忍者里鸣人的影分身么?没错,PHP程序是可以开动影分身的!想完成任务,又觉得一个进程太慢,那么,试试用多进程来搞吧.这篇文章将会介绍一下PHP多进程的基本需求,如何创建多进程以及基本的信号控制,暂时不会告诉你如何进行进程间通信和信息共享. 1. 准备 在动手之前,请确定你用的不是M$ Windows平台(因为我没有Windows).Lin