linux php 进程初探(一) fork

Fork

基本概念

  1. 一个进程,包括代码、数据和分配给进程的资源。fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
  2. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
  3. fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次(实际会执行两次,第一次可能是父进程,第二次可能是子进程),它可能有三种不同的返回值:
  1. 在父进程中,fork返回新创建子进程的进程ID;
  2. 在子进程中,fork返回0;
  3. 如果出现错误,fork返回一个负值;
  1. 在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

  2. fork出错可能有两种原因:

  1. 当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
  2. 系统内存不足,这时errno的值被设置为ENOMEM。
  1. 在php中我们使用 pcntl_fork() 来创建多进程。fork出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。这里要注意:

    • 子进程与父进程共享程序正文段
    • 子进程拥有父进程的数据空间和堆、栈的副本,注意是副本,不是共享
    • 父进程和子进程将继续执行fork之后的程序代码
    • fork之后,是父进程先执行还是子进程先执行无法确认,取决于系统调度
  2. 这里说子进程拥有父进程数据空间以及堆、栈的副本,实际上,在大多数的实现中也并不是真正的完全副本。更多是采用了COW(Copy On Write)即写时复制的技术来节约存储空间。简单来说,如果父进程和子进程都不修改这些 数据、堆、栈 的话,那么父进程和子进程则是暂时共享同一份 数据、堆、栈。只有当父进程或者子进程试图对 数据、堆、栈 进行修改的时候,才会产生复制操作,这就叫做写时复制。

  3. 在调用完pcntl_fork()后,该函数会返回两个值。在父进程中返回子进程的进程ID,在子进程内部本身返回数字0。由于多进程在apache或者fpm环境下无法正常运行,所以大家一定要在php cli环境下执行下面php代码。

注意:不要在apache或者fpm环境下使用php多进程,这将会产生不可预估的后果。

  1. 下面是php语言 pcntl_fork() 函数实例代码(注意代码注释标注有父子进程的执行代码块
<?php
$pid = pcntl_fork();#1 // 父进程从当前行开始运行
if($pid > 0){#2 // 本行会有两个进程运行,一个是子进程,一个是父进程,子进程从当前行开始运行而父进程从上一行开始运行,当前行之前的代码子进程并不会执行。
    echo "我是父进程".PHP_EOL;#3
}else if($pid == 0){#4
    echo "我是子进程".PHP_EOL;#5
}else{#6
    echo "fork 进程错误".PHP_EOL;#7
}#8

代码执行逻辑(#后面数字代表行数,方便理解):

  1. 父进程从#1行代码开始运行,执行 pcntl_fork函数
  2. 这个函数执行成功后,会创建一个子进程(子进程会复制父进程的代码段(正文段)和数据段)
  3. 然后父进程执行#2行判断echo输出后进程结束,子进程从#2行开始执行,echo输出后进程结束

需要特别注意的是:当父进程调用pcntl_fork函数后,创建出来子进程,这时有两个进程,哪个进程先运行无法确定,是由操作系统决定,进程调度由系统决定。
一般情况下 都是父进程先运行,子进程后运行,如果父进程先运行先结束,剩下的子进程就会变成孤儿进程,不清楚孤儿进程是什么的的可以看我这篇文章 linux php 进程进阶(二) 孤儿进程

在这里插入图片描述
2. 第二段代码,用来说明子进程拥有父进程的数据副本,并不是共享

<?php
$num = 1;
$pid = pcntl_fork();
if($pid > 0){
$num += 2;
echo "我是父进程 num:$num".PHP_EOL;
}else if($pid == 0){
$num += 1;
echo "我是子进程 num:$num".PHP_EOL;
}else{
echo "进程 fork 错误".PHP_EOL;
}

在这里插入图片描述

  1. 第3段代码使用for循环使用pcntl_fork,循环4次猜猜会出现几个我是子进程? 是15个子进程
<?php
for($i=1; $i<=5; $i++){
	$pid = pcntl_fork();
	if($pid > 0){
	}else if($pid == 0){
		echo "我是子进程 i:$i".PHP_EOL;
	}else{
		echo "进程 fork 错误".PHP_EOL;
	}
}

总结一下规律,对于这种N次循环的情况,执行 echo 函数的次数为2*(1+2+4+……+ 2 N 2^N 2N − 1 -1 1)次,创建的子进程数为1+2+4+……+ 2 N 2^N 2N − 1 -1 1个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
进程编程是一种应用在Unix/Linux系统中的编程方法,其中一个重要的概念就是fork(分叉)。 在Linux中,fork是一个系统调用,它创建一个新的进程。通过fork,父进程可以生成一个与自己完全相同的子进程。父进程和子进程之间的唯一区别在于它们的进程ID不同,其他方面都是一模一样的。 fork的作用是允许一个进程创建一个与自己共享资源的进程,但是拥有独立的执行空间。这样可以避免不同进程之间相互影响和干扰。 在使用fork的过程中,操作系统会将父进程的所有信息(包括代码、数据、打开的文件描述符等)拷贝一份给子进程。然后,父进程和子进程会从fork调用的返回值中得到不同的结果。在父进程中,返回的是子进程进程ID;在子进程中,返回的是0。这样,父进程就可以根据fork的返回值来判断自己是父进程还是子进程,从而进行不同的操作。 在实际的编程中,可以通过fork来实现各种不同的功能。比如,可以通过fork创建一个子进程来进行并发执行,提高程序的运行效率。另外,可以通过fork来创建一个子进程来执行一段代码,然后通过父进程来等待子进程的结束并处理子进程的结果。 总之,进程编程中的fork是一个非常重要且常用的概念,它提供了创建和管理进程的能力,为程序的并发执行和资源的管理提供了可能。

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值