[原文地址:https://blog.ti-node.com/blog...]php
实际上PHP是有多线程的,只是不少人不经常使用。使用PHP的多线程首先须要下载安装一个线程安全版本(ZTS版本)的PHP,而后再安装pecl的pthread扩展。node
实际上PHP是有多进程的,有一些人再用,整体来讲php的多进程还算凑合,只须要在安装PHP的时候开启pcntl模块(是否是跟UNIX中的fcntl有点儿.... ....)便可。在*NIX下,在终端命令行下使用php -m就能够看到是否开启了pcntl模块。nginx
因此咱们只说php的多进程,至于php多线程就暂时放到一边儿。apache
注意:不要在apache或者fpm环境下使用php多进程,这将会产生不可预估的后果。编程
进程是程序执行的实例,举个例子有个程序叫作 “ 病毒.exe ”,这个程序平时是以文件形式存储在硬盘上,当你双击运行后,就会造成一个该程序的进程。系统会给每个进程分配一个惟一的非负整数用来标记进程,这个数字称做进程ID。当该进程被杀死或终止后,其进程ID就会被系统回收,而后分配给新的其他的进程。安全
说了这么多,这鬼东西有什么用吗?我平时用CI、YII写个CURD跟这个也没啥关联啊。实际上,若是你了解APACHE PHP MOD或者FPM就知道这些东西就是多进程实现的。以FPM为例,通常都是nginx做为http服务器挡在最前面,静态文件请求则nginx自行处理,遇到php动态请求则转发给php-fpm进程来处理。若是你的php-fpm配置只开了5个进程,若是处理任意一个用户的请求都须要1秒钟,那么5个fpm进程1秒中就最多只能处5个用户的请求。因此结论就是:若是要单位时间内干活更快更多,就须要更多的进程,总之一句话就是多进程能够加快任务处理速度。服务器
在php中咱们使用pcntl_fork()来建立多进程(在*NIX系统的C语言编程中,已有进程经过调用fork函数来产生新的进程)。fork出来新进程则成为子进程,原进程则成为父进程,子进程拥有父进程的副本。这里要注意:多线程
这里说子进程拥有父进程数据空间以及堆、栈的副本,实际上,在大多数的实现中也并非真正的彻底副本。更可能是采用了COW(Copy On Write)即写时复制的技术来节约存储空间。简单来讲,若是父进程和子进程都不修改这些 数据、堆、栈 的话,那么父进程和子进程则是暂时共享同一份 数据、堆、栈。只有当父进程或者子进程试图对 数据、堆、栈 进行修改的时候,才会产生复制操做,这就叫作写时复制。函数
在调用完pcntl_fork()后,该函数会返回两个值。在父进程中返回子进程的进程ID,在子进程内部自己返回数字0。因为多进程在apache或者fpm环境下没法正常运行,因此你们必定要在php cli环境下执行下面php代码。php-fpm
第一段代码,咱们来讲明在程序从pcntl_fork()后父进程和子进程将各自继续往下执行代码:
<?php $pid = pcntl_fork(); if( $pid > 0 ){ echo "我是父亲".PHP_EOL; } else if( 0 == $pid ) { echo "我是儿子".PHP_EOL; } else { echo "fork失败".PHP_EOL; }
将文件保存为test.php,而后在使用cli执行,结果以下图所示:
第二段代码,用来讲明子进程拥有父进程的数据副本,而并非共享:
<?php // 初始化一个 number变量 数值为1 $number = 1; $pid = pcntl_fork(); if( $pid > 0 ){ $number += 1; echo "我是父亲,number+1 : { $number }".PHP_EOL; } else if( 0 == $pid ) { $number += 2; echo "我是父亲,number+2 : { $number }".PHP_EOL; } else { echo "fork失败".PHP_EOL; }
第三段代码,比较容易让人思惟混乱,pcntl_fork()配合for循环来作些东西,问题来了:会显示几回 “ 儿子 ”?
<?php for( $i = 1; $i <= 3 ; $i++ ){ $pid = pcntl_fork(); if( $pid > 0 ){ // do nothing ... } else if( 0 == $pid ){ echo "儿子".PHP_EOL; } }
上面代码执行结果以下:
仔细数数,居然是显示了7次 “ 儿子 ”。好奇怪,难道不是3次吗?... ...
下面我修改一下代码,结合下面的代码,再思考一下为何会产生7次而不是3次。
<?php for( $i = 1; $i <= 3 ; $i++ ){ $pid = pcntl_fork(); if( $pid > 0 ){ // do nothing ... } else if( 0 == $pid ){ echo "儿子".PHP_EOL; exit; } }
执行结果以下图所示:
前面强调过:父进程和子进程将继续执行fork以后的程序代码。这里就不解释,实在想不明白的,能够动手本身画画思考一下。
为了不写成臭尾理论文儿,这里强行断篇分割一下,下一章说僵尸进程和孤儿进程的一些恩怨情仇。