免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
123
最近访问板块 发新帖
楼主: HonestQiao

[学习] PHP中的(伪)多线程与多进程 [复制链接]

论坛徽章:
0
发表于 2005-12-06 11:40 |显示全部楼层
原帖由 wobushiwo 于 2005-12-2 20:38 发表
不好意思,是 + &



请看 13 楼

论坛徽章:
0
发表于 2006-06-02 11:38 |显示全部楼层
除了fork, cli下的并发方式还有一种,看我的例子:


php不支持多线程,但是我们可以把问题转换成“多进程”来解决。由于php中的pcntl_fork只有unix平台才可以使用,所以本文尝试使用popen来替代。


下面是一个例子:

被并行调用的子程序代码:

  1. <?php

  2. if($argc==1){
  3. echo("argv\n");
  4. }

  5. $arg = $argv[1];

  6. for($i=0; $i<10; $i++)
  7. {

  8. echo($i.".1.".time()." exec $arg \n");
  9. if($arg=='php2')
  10. {
  11. sleep(1);
  12. echo($i.".2.".time()." exec $arg \n");
  13. sleep(1);
  14. }
  15. else
  16. sleep(1);
  17. }


  18. ?>
复制代码

----------------------------

主调用者程序,由他调用子进程,同时并发的收集子程序的输出

  1. <?php
  2. error_reporting(E_ALL);


  3. $handle1 = popen('php sub.php php1', 'r');
  4. $handle2 = popen('php sub.php php2', 'r');
  5. $handle3 = popen('php sub.php php3', 'r');


  6. echo "'$handle1'; " . gettype($handle1) . "\n";
  7. echo "'$handle2'; " . gettype($handle2) . "\n";
  8. echo "'$handle3'; " . gettype($handle3) . "\n";

  9. //sleep(20);

  10. while(!feof($handle1) || !feof($handle2) || !feof($handle3) )
  11. {

  12. $read = fgets($handle1);
  13. echo $read;

  14. $read = fgets($handle2);
  15. echo $read;

  16. $read = fgets($handle3);
  17. echo $read;
  18. }

  19. pclose($handle1);
  20. pclose($handle2);
  21. pclose($handle3);
  22. ?>
复制代码

-------------------
下面是我机器上的输出:

C:\my_hunter>php exec.php
'Resource id #4'; resource
'Resource id #5'; resource
'Resource id #6'; resource
0.1.1147935331 exec php1
0.1.1147935331 exec php2
0.1.1147935331 exec php3
1.1.1147935332 exec php1
0.2.1147935332 exec php2
1.1.1147935332 exec php3
2.1.1147935333 exec php1
1.1.1147935333 exec php2
2.1.1147935333 exec php3
3.1.1147935334 exec php1
1.2.1147935334 exec php2
3.1.1147935334 exec php3
4.1.1147935335 exec php1
2.1.1147935335 exec php2
4.1.1147935335 exec php3
5.1.1147935336 exec php1
2.2.1147935336 exec php2
5.1.1147935336 exec php3
6.1.1147935337 exec php1
3.1.1147935337 exec php2
6.1.1147935337 exec php3
7.1.1147935338 exec php1
3.2.1147935338 exec php2
7.1.1147935338 exec php3
8.1.1147935339 exec php1
4.1.1147935339 exec php2
8.1.1147935339 exec php3
9.1.1147935340 exec php1
4.2.1147935340 exec php2
9.1.1147935340 exec php3
5.1.1147935341 exec php2
5.2.1147935342 exec php2
6.1.1147935343 exec php2
6.2.1147935344 exec php2
7.1.1147935345 exec php2
7.2.1147935346 exec php2
8.1.1147935347 exec php2
8.2.1147935348 exec php2
9.1.1147935349 exec php2
9.2.1147935350 exec php2



**总结:**

**主程序循环等待子进程, 通过fgets或fread 把子进程的输出获取出来 , 从时间戳上看,的确实现了并发执行。**

-----------------------------------------------
以后的改进:

*  popen打开的句柄是单向的,如果需要向子进程交互,可以使用proc_open
*  使用数组和子函数代替while(!feof($handle1) || !feof($handle2) || !feof($handle3) )这种龌龊的写法
*  用fread一次把子进程已经产生的输出取完,而不是每次一行。

------------------
我的blog : http://dulao5.blog.hexun.com/3726837_d.html

[ 本帖最后由 dulao5 于 2006-6-2 11:39 编辑 ]

论坛徽章:
0
发表于 2006-06-02 11:45 |显示全部楼层
一个并发执行shell任务的调度者,本程序读取一个任务文件,把里面的每行命令并发执行, 可以设置同时存在的子进程数目:


  1. <?
  2. /*
  3.    主任务管理器
  4.    并发的执行子任务列表
  5. */

  6. include("../common/conf.php");
  7. include("../common/function.php");

  8. //开启的进程数
  9. $exec_number = 40 ;



  10. /***** main ********/
  11. if($argc==1){
  12.     echo("argv\n");
  13. }
  14. $taskfile = $argv[1];

  15. //tasklist
  16. $tasklist = file($taskfile);

  17. $tasklist_len = count($tasklist);
  18. $tasklist_pos = 0;

  19. $handle_list = array();



  20. while(1)
  21. {

  22.     //子进程列表有空闲,则填充补齐子进程列表
  23.     if($exec_number > count($handle_list) &&
  24.             $tasklist_pos < $tasklist_len)
  25.     {

  26.         for($i=$tasklist_pos; $i<$tasklist_len; )
  27.         {
  28.             $command = $tasklist[$i] ;
  29.             $handle_list[] = popen($command , "r" );
  30.             tolog("begin task \t ".$tasklist[$i]);
  31.             $i++;
  32.             if($exec_number == count($handle_list)) break;
  33.         }
  34.         $tasklist_pos = $i;
  35.     }

  36.     //如果子进程列表空,退出
  37.     if(0 == count($handle_list))
  38.     {
  39.         break;
  40.     }

  41.     //检查子进程列表的输出,把停掉的子进程关闭并记录下来
  42.     $end_handle_keys = array();
  43.     foreach($handle_list as $key => $handle)
  44.     {
  45.         //$str = fgets($handle, 65536);
  46.         $str = fread($handle, 65536);
  47.         echo($str);

  48.         if(feof($handle))
  49.         {
  50.             $end_handle_keys[] = $key;
  51.             pclose($handle);
  52.         }
  53.     }

  54.     //踢出停掉的子进程
  55.     foreach($end_handle_keys as $key)
  56.     {
  57.         unset($handle_list[$key]);
  58.         //var_dump($handle_list);
  59.         //exit;
  60.     }


  61. }

  62. tolog("\n\n*******************end**********************\n\n", "" ,  true);

  63. ?>
复制代码

论坛徽章:
0
发表于 2006-06-05 16:25 |显示全部楼层
如果b.php中的用了require_once或require等再调用一个类
$test = new test();
这个类根本没有执行!
这样只是对当前页有效也就是说echo ,file之类!大家都不要把所有程序都用一页php来写完吧?

论坛徽章:
0
发表于 2007-11-22 12:59 |显示全部楼层
PHP还是PHP 多线程还是交给C吧

论坛徽章:
0
发表于 2007-11-26 09:00 |显示全部楼层
我不是很赞同这样来实现PHP伪多线程,我曾经做过一个爬网页的程序,是用来制作sitemap的。其中解决多线程的手段是数据库加上AJAX来完成的,这样比较安全,容易控制。

论坛徽章:
0
发表于 2007-11-29 16:21 |显示全部楼层
意义不大

论坛徽章:
0
发表于 2008-06-06 16:55 |显示全部楼层
技术性超强的帖!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

【CUer福利】柯尼卡美能达2018数字化整合解决方案巡展
智领共创链动价值-2018数字化整合解决方案巡展

2018年11月,柯尼卡美能达携手主流IT网络媒体IT168及旗下ITPUB、ChinaUnix等论坛,特此邀请企业IT管理、运维人员/办公设备采购负责人员共同参与,分享柯尼卡美能达“智领共创链动价值”-2018数字化整合解决方案巡展!现场体验MOBOTIX智能视频监控解决方案!

活动入口>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:wangnan@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP