当前位置:首页 > PHP教程 > php高级应用 > 列表

简单的php多线程解决方法

发布:smiling 来源: PHP粉丝网  添加日期:2022-06-30 09:13:26 浏览: 评论:0 

我们在做项目的时候,有些需求,特别是数据的响应处理需要花费大量的时间,由于php是一个短生命周期的脚本语言,到了默认的30秒,php的数据处理还没完成,php的生命周期就结束了。

这时需要使用异步并发处理策略,也就是说,一次php调用可以发出的多个请求,这些请求不是按照顺序执行,而是可以异步并发执行的,一些请求用于在后台处理数据,一些请求用于接受后台响应状态,根据状态,与用户做一些简单的交互。

但是问题来了,我们都知道php本身是不支持多线程的,那么应该怎么实现php的多线程呢?

一、php模拟实现多线程的三种方法

1、linux下的php多线程

下面所讲的东西是源自php的pcntl_fork函数.因为这个函数依赖操作系统fork的实现,所以本文所讲的东西只适用于linux/unix。那么先看看这个函数的用法吧.php手册上是这么说的:

  1. <?php 
  2.  
  3. $pid = pcntl_fork(); 
  4.  
  5. if ($pid == -1) { 
  6.  
  7.          die('could not fork'); 
  8.  
  9. else if ($pid) { 
  10.  
  11.          // we are the parent 
  12.  
  13.          pcntl_wait($status); //Protect against Zombie children 
  14.  
  15. else { 
  16.  
  17.          // we are the child 
  18.  
  19.  
  20. ?> 

通过pcntl_fork创建一个子进程,如果返回值是-1的话,那么说明子进程创建失败.创建成功的进程id会返回给父进程,0返回给子进程.不好理解吧,所以应该这样写:

  1. <?php 
  2.  
  3. $pid = pcntl_fork(); 
  4.  
  5. if($pid == -1){ 
  6.  
  7.          //创建失败咱就退出呗,没啥好说的 
  8.  
  9.          die('could not fork'); 
  10.  
  11.  
  12. else
  13.  
  14.         if($pid){ 
  15.  
  16.                 //从这里开始写的代码是父进程的,因为写的是系统程序,记得退出的时候给个返回值 
  17.  
  18.                 exit(0); 
  19.  
  20.         } 
  21.  
  22.         else
  23.  
  24.                 //从这里开始写的代码都是在新的进程里执行的,同样正常退出的话,最好也给一个返回值 
  25.  
  26.                 exit(0); 
  27.  
  28.         } 
  29.  
  30.  
  31. ?> 

这样一改好理解多了,如果你父进程希望知道子进程正常退出的话,可以加上前面的pcntl_wait。

2.通过stream_socket_client 方式

  1. function sendStream() {  
  2.  
  3.     $english_format_number = number_format($number, 4, '.''');  
  4.  
  5.     
  6.  
  7.     echo $english_format_number;   
  8.  
  9.     exit();  
  10.  
  11.     $timeout = 10;  
  12.  
  13.     $result = array();  
  14.  
  15.     $sockets = array();  
  16.  
  17.     $convenient_read_block = 8192;  
  18.  
  19.     $host = "test.local.com";  
  20.  
  21.     $sql = "select waybill_id,order_id from xm_waybill where status>40 order by update_time desc limit 1 ";   
  22.  
  23.     $data = Yii::app()->db->createCommand($sql)->queryAll();  
  24.  
  25.     $id = 0;  
  26.  
  27.     
  28.  
  29.     foreach ($data as $k => $v) {  
  30.  
  31.       if ($k % 2 == 0) {  
  32.  
  33.         $send_data[$k]['body'] = NoticeOrder::getSendData($v['waybill_id']);  
  34.  
  35.     
  36.  
  37.       } else {  
  38.  
  39.         $send_data[$k]['body'] = array($v['order_id'] => array('extra' => 16));   
  40.  
  41.       }   
  42.  
  43.       $data = json_encode($send_data[$k]['body']);  
  44.  
  45.       $s = stream_socket_client($host . ":80"$errno$errstr$timeout, STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT);  
  46.  
  47.       if ($s) {   
  48.  
  49.         $sockets[$id++] = $s;  
  50.  
  51.         $http_message = "GET /php/test.php?data=" . $data . " HTTP/1.0 
  52.  
  53. Host:" . $host . " 
  54.  
  55. ";   
  56.  
  57.         fwrite($s$http_message);  
  58.  
  59.       } else {   
  60.  
  61.         echo "Stream " . $id . " failed to open correctly.";  
  62.  
  63.       }   
  64.  
  65.     }  
  66.  
  67.     
  68.  
  69.     while (count($sockets)) {  
  70.  
  71.     
  72.  
  73.       $read = $sockets;  
  74.  
  75.     
  76.  
  77.       stream_select($read$w = null, $e = null, $timeout);  
  78.  
  79.        if (count($read)) {   
  80.  
  81.         /* stream_select generally shuffles $read, so we need to  
  82.  
  83.          compute from which socket(s) we're reading. */ 
  84.  
  85.         foreach ($read as $r) {  
  86.  
  87.     
  88.  
  89.           $id = array_search($r$sockets);  
  90.  
  91.           $data = fread($r$convenient_read_block);  
  92.  
  93.           if (strlen($data) == 0) {  
  94.  
  95.             echo "Stream " . $id . " closes at " . date('h:i:s') . ".<br>  ";  
  96.  
  97.             fclose($r);  
  98.  
  99.              unset($sockets[$id]);  
  100.  
  101.           } else {  
  102.  
  103.             $result[$id] = $data;  
  104.  
  105.           }  
  106.  
  107.         }  
  108.  
  109.       } else {   
  110.  
  111.         /* A time-out means that *all* streams have failed  
  112.  
  113.          to receive a response. */ 
  114.  
  115.         echo "Time-out! 
  116.  
  117. ";  
  118.  
  119.         break;  
  120.  
  121.       }   
  122.  
  123.     }   
  124.  
  125.     print_r($result);  
  126.  
  127.     
  128.  
  129.   } 

3、通过多进程代替多线程

  1. function daemon($func_name,$args,$number){  
  2.  
  3.   while(true){  
  4.  
  5.     $pid=pcntl_fork();  
  6.  
  7.     if($pid==-1){  
  8.  
  9.       echo "fork process fail";  
  10.  
  11.       exit();  
  12.  
  13.     }elseif($pid){//创建的子进程  
  14.  
  15.     
  16.  
  17.       static $num=0;  
  18.  
  19.       $num++;  
  20.  
  21.       if($num>=$number){  
  22.  
  23.         //当进程数量达到一定数量时候,就对子进程进行回收。  
  24.  
  25.         pcntl_wait($status);  
  26.  
  27.     
  28.  
  29.         $num--;  
  30.  
  31.       }   
  32.  
  33.     }else//为0 则代表是子进程创建的,则直接进入工作状态  
  34.  
  35.     
  36.  
  37.       if(function_exists($func_name)){  
  38.  
  39.         while (true) {  
  40.  
  41.           $ppid=posix_getpid();  
  42.  
  43.           var_dump($ppid);  
  44.  
  45.           call_user_func_array($func_name,$args);  
  46.  
  47.           sleep(2);  
  48.  
  49.         }  
  50.  
  51.       }else{  
  52.  
  53.         echo "function is not exists";  
  54.  
  55.       }  
  56.  
  57.       exit();    
  58.  
  59.     }  
  60.  
  61.   }  
  62.  
  63. }   
  64.  
  65. function worker($args){   
  66.  
  67.   //do something  
  68.  
  69.     
  70.  
  71. }   
  72.  
  73. daemon('worker',array(1),2); 

二、真正实现php多线程的方法

php真正的多线程实现方式,通过安装php的扩展 pthread 可以做到。

点此下载https://github.com/krakjoe/pthreads 但是这个下载的是 版本3 也就是php 7 才能用的,我们需要使的是 版本2

简单的php多线程解决方法

然后刷新的页面如下,拖到最底部:

简单的php多线程解决方法

下一页找到版本2的

下载下来,这个v2 才是php5才可以使用的

下载下来,安装:

或者,您直接这样下载:

  1. cd /tools   
  2.  
  3.    wget https://github.com/krakjoe/pthreads/archive/v2.0.10.zip   
  4.  
  5.    unzip   v2.0.10.zip   
  6.  
  7.    cd pthreads-2.0.10   
  8.  
  9.    /usr/local/php/bin/phpize   
  10.  
  11.    ./configure --with-php-config=/usr/local/php/bin/php-config     
  12.  
  13.    make   
  14.  
  15.    make install 

注意:您的php 在编译的时候需要开启 –enable-maintainer-zts

./configure --prefix=/usr/local/php --disable-fileinfo --enable-fpm --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-openssl --with-zlib --with-curl --enable-ftp --with-gd --with-xmlrpc --with-jpeg-dir --with-png-dir --with-freetype-dir --enable-gd-native-ttf --enable-mbstring --with-mcrypt=/usr/local/libmcrypt --enable-zip --with-mysql=/usr/local/mysql --without-pear --enable-maintainer-zts

vim /etc/php.ini

添加:

extension=pthreads.so

重启php /etc/init.d/php-fpm restart

Tags: php多线程

分享到: