PHP 多进程
来源:互联网 发布:域名劫持软件 编辑:程序博客网 时间:2024/06/17 19:15
</pre><span style="padding:0px; margin:0px; color:rgb(51,51,51); font-family:微软雅黑,Verdana,sans-serif,宋体; font-size:13px; line-height:22.5px"></span><pre name="code" class="php"><span style="color: rgb(51, 51, 51); font-family: 微软雅黑, Verdana, sans-serif, 宋体; font-size: 13px; line-height: 22.5px; background-color: rgb(255, 255, 255);">1直接方式</span>
<span style="color: rgb(51, 51, 51); font-family: 微软雅黑, Verdana, sans-serif, 宋体; font-size: 13px; line-height: 22.5px; background-color: rgb(255, 255, 255);">pcntl_fork() 创建一个进程,在父进程返回值是子进程的pid,在子进程返回值是0,-1表示创建进程失败。跟C非常相似。 </span>
测试脚本 test.php
date_default_timezone_set('Asia/Chongqing'); echo"parent start, pid ",getmypid(),"\n"; beep(); for($i=0;$i<3; ++$i){ $pid= pcntl_fork(); if($pid== -1){ die("cannot fork" ); }elseif($pid> 0){ echo"parent continue \n"; for($k=0;$k<2; ++$k){ beep(); } }elseif($pid== 0){ echo"child start, pid ",getmypid(),"\n"; for($j=0;$j<5; ++$j){ beep(); } exit; } } // *** functionbeep(){ echogetmypid(),"\t",date('Y-m-d H:i:s', time()), "\n"; sleep(1); }
输出结果
parent start, pid 1793
1793 2013-01-14 15:04:17
parent continue
1793 2013-01-14 15:04:18
child start, pid 1794
1794 2013-01-14 15:04:18
1794 2013-01-14 15:04:19
1793 2013-01-14 15:04:19
1794 2013-01-14 15:04:20
parent continue
1793 2013-01-14 15:04:20
child start, pid 1795
1795 2013-01-14 15:04:20
17931794 2013-01-14 15:04:212013-01-14 15:04:21
1795 2013-01-14 15:04:21
1794 2013-01-14 15:04:22
1795 2013-01-14 15:04:22
parent continue
1793 2013-01-14 15:04:22
child start, pid 1796
1796 2013-01-14 15:04:22
1793 2013-01-14 15:04:23
1796 2013-01-14 15:04:23
1795 2013-01-14 15:04:23
1795 2013-01-14 15:04:24
1796 2013-01-14 15:04:24
1796 2013-01-14 15:04:25
1796 2013-01-14 15:04:26
从中看到,创建了3个子进程,和父进程一起并行运行。其中有一行格式跟其他有些不同,
17931794 2013-01-14 15:04:212013-01-14 15:04:21
因为两个进程同时进行写操作,造成了冲突。
2. 阻塞方式
用直接方式,父进程创建了子进程后,并没有等待子进程结束,而是继续运行。似乎这里看不到有什么问题。如果php脚本并不是运行完后自动结束,而是常驻内存的,就会造成子进程无法回收的问题。也就是僵尸进程。可以通过pcntl_wai()方法等待进程结束,然后回收已经结束的进程。
将测试脚本改成:
$pid= pcntl_fork();if($pid== -1){ ...}elseif($pid> 0){ echo"parent continue \n"; pcntl_wait($status); for($k=0;$k<2; ++$k){ beep(); }}elseif($pid== 0){ ...}
#php -f test.php
输出结果
parent start, pid 1807
1807 2013-01-14 15:20:05
parent continue
child start, pid 1808
1808 2013-01-14 15:20:06
1808 2013-01-14 15:20:07
1808 2013-01-14 15:20:08
1808 2013-01-14 15:20:09
1808 2013-01-14 15:20:10
1807 2013-01-14 15:20:11
1807 2013-01-14 15:20:12
parent continue
child start, pid 1809
1809 2013-01-14 15:20:13
1809 2013-01-14 15:20:14
1809 2013-01-14 15:20:15
1809 2013-01-14 15:20:16
1809 2013-01-14 15:20:17
1807 2013-01-14 15:20:18
1807 2013-01-14 15:20:19
child start, pid 1810
1810 2013-01-14 15:20:20
parent continue
1810 2013-01-14 15:20:21
1810 2013-01-14 15:20:22
1810 2013-01-14 15:20:23
1810 2013-01-14 15:20:24
1807 2013-01-14 15:20:25
1807 2013-01-14 15:20:26
父进程在pcntl_wait()将自己阻塞,等待子进程运行完了才接着运行。
3. 非阻塞方式
阻塞方式失去了多进程的并行性。还有一种方法,既可以回收已经结束的子进程,又可以并行。这就是非阻塞的方式。
修改脚本:
用命令行运行
<?php // example of multiple processes date_default_timezone_set('Asia/Chongqing'); declare(ticks = 1); pcntl_signal(SIGCHLD,"garbage"); echo"parent start, pid ",getmypid(),"\n"; beep(); for($i=0;$i<3; ++$i){ $pid= pcntl_fork(); if($pid== -1){ die("cannot fork" ); }elseif($pid> 0){ echo"parent continue \n"; for($k=0;$k<2; ++$k){ beep(); } }elseif($pid== 0){ echo"child start, pid ",getmypid(),"\n"; for($j=0;$j<5; ++$j){ beep(); } exit(0); } } // parent while(1){ // do something else sleep(5); } // *** functiongarbage($signal){ echo"signel $signal received\n" ; while(($pid= pcntl_waitpid(-1, $status, WNOHANG))> 0){ echo"\t child end pid $pid , status $status\n" ; } } functionbeep(){ echogetmypid(),"\t",date('Y-m-d H:i:s', time()), "\n"; sleep(1); }?>
输出结果
parent start, pid 2066
2066 2013-01-14 16:45:34
parent continue
2066 2013-01-14 16:45:35
child start, pid 2067
2067 2013-01-14 16:45:35
20662067 2013-01-14 16:45:362013-01-14 16:45:36
2067 2013-01-14 16:45:37
parent continue
2066 2013-01-14 16:45:37
child start, pid 2068
2068 2013-01-14 16:45:37
2067 2013-01-14 16:45:38
2068 2013-01-14 16:45:38
2066 2013-01-14 16:45:38
parent continue
2066 2013-01-14 16:45:40
child start, pid 2069
2069 2067 2013-01-14 16:45:40
2013-01-14 16:45:40
2068 2013-01-14 16:45:40
2066 2013-01-14 16:45:41
2069 2013-01-14 16:45:41
2068 2013-01-14 16:45:41
signel 17 received
child end pid 2067, status 0
2069 2013-01-14 16:45:42
2068 2013-01-14 16:45:42
2069 2013-01-14 16:45:43
signel 17 received
child end pid 2068, status 0
2069 2013-01-14 16:45:44
signel 17 received
child end pid 2069, status 0
多个进程又并行运行了,而且运行大约10秒钟之后,用 ps -ef | grep php 查看正在运行的进程,只有一个进程
lqling 2066 1388 0 16:45 pts/1 00:00:00 php -f t5.php
是父进程,子进程被回收了。
4. 子进程退出状态
pcntl_waitpid(-1, $status, WNOHANG) $status 返回子进程的结束状态
5. windows多线程
windows系统不支持pcntl函数,幸好有curl_multi_exec()这个工具,利用内部的多线程,访问多个链接,每个链接可以作为一个任务。
编写脚本 test1.php
<?php date_default_timezone_set('Asia/Chongqing'); $tasks=array( 'http://localhost/feedbowl/t2.php?job=task1', 'http://localhost/feedbowl/t2.php?job=task2', 'http://localhost/feedbowl/t2.php?job=task3' ); $mh= curl_multi_init(); foreach($tasksas$i => $task){ $ch[$i] = curl_init(); curl_setopt($ch[$i], CURLOPT_URL, $task); curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1); curl_multi_add_handle($mh,$ch[$i]); } do{$mrc= curl_multi_exec($mh,$active); } while($mrc== CURLM_CALL_MULTI_PERFORM); while($active&&$mrc== CURLM_OK) { if(curl_multi_select($mh) != -1) { do{$mrc= curl_multi_exec($mh,$active); } while($mrc== CURLM_CALL_MULTI_PERFORM); } } // completed, checkout result foreach($tasksas$j => $task){ if(curl_error($ch[$j])){ echo"task ${j} [$task ] error " , curl_error($ch[$j]),"\r\n"; }else{ echo"task ${j} [$task ] get: \r\n" , curl_multi_getcontent($ch[$j]),"\r\n"; } }?>
编写脚本 test2.php
<?php date_default_timezone_set('Asia/Chongqing'); echo"child start, pid ",getmypid(),"\r\n"; for($i=0;$i<5; ++$i){ beep(); } exit(0); // *** functionbeep(){ echogetmypid(),"\t",date('Y-m-d H:i:s' , time()), "\r\n"; sleep(1); }?>
输出结果
task 0 [http://localhost/feedbowl/t2.php?job=task1] get:
child start, pid 5804
5804 2013-01-15 20:22:35
5804 2013-01-15 20:22:36
5804 2013-01-15 20:22:37
5804 2013-01-15 20:22:38
5804 2013-01-15 20:22:39
task 1 [http://localhost/feedbowl/t2.php?job=task2] get:
child start, pid 5804
5804 2013-01-15 20:22:35
5804 2013-01-15 20:22:36
5804 2013-01-15 20:22:37
5804 2013-01-15 20:22:38
5804 2013-01-15 20:22:39
task 2 [http://localhost/feedbowl/t2.php?job=task3] get:
child start, pid 5804
5804 2013-01-15 20:22:35
5804 2013-01-15 20:22:36
5804 2013-01-15 20:22:37
5804 2013-01-15 20:22:38
5804 2013-01-15 20:22:39
从打印的时间看到,多个任务几乎是同时运行的。
0 0
- PHP多进程编程
- php多进程
- PHP多进程编程
- PHP的多进程
- php的多进程
- PHP的多进程
- PHP多进程编程
- php cli多进程
- PHP多进程
- php多进程实现
- PHP的多进程
- PHP多进程编程
- PHP 多进程
- php 多进程思路
- php 多进程处理
- PHP多进程实例
- php多进程处理
- php多进程实现
- IOS Container Autolayout
- cadence.通孔类封装创建
- 统计IP
- 【Code Forces】518A Vitaly and Strings(思维题)
- Window下命令行编译C/C++
- PHP 多进程
- 高并发高流量网站架构(转)
- 吴恩达 机器学习笔记 Linear Regression with Multiple Variables
- Print A Tree In Vertical Order
- 原码、反码、补码及移位操作
- ireport 的一些技巧
- 吴恩达 机器学习 笔记 some tips on applying machine Learning
- 反汇编之流程控制语句的识别(if...else...语句)
- 浅谈 android ANR 如何找有用的信息