• 通俗易懂的php多线程解决方案


    我们在做项目的时候,有些需求,特别是数据的响应处理需要花费大量的时间,由于php是一个短生命周期的脚本语言,到了默认的30秒,php的数据处理还没完成,php的生命周期就结束了。这时需要使用异步并发处理策略,也就是说,一次php调用可以发出的多个请求,这些请求不是按照顺序执行,而是可以异步并发执行的,一些请求用于在后台处理数据,一些请求用于接受后台响应状态,根据状态,与用户做一些简单的交互。但是问题来了,我们都知道php本身是不支持多线程的,那么应该怎么实现php的多线程呢?

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

    1、linux下的php多线程

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

    <?php
    $pid = pcntl_fork();
    if ($pid == -1) {
             die('could not fork');
    } else if ($pid) {
             // we are the parent
             pcntl_wait($status); //Protect against Zombie children
    } else {
             // we are the child
    }
    ?>

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

    <?php
    $pid = pcntl_fork();
    if($pid == -1){
             //创建失败咱就退出呗,没啥好说的
             die('could not fork');
    }
    else{
            if($pid){
                    //从这里开始写的代码是父进程的,因为写的是系统程序,记得退出的时候给个返回值
                    exit(0);
            }
            else{
                    //从这里开始写的代码都是在新的进程里执行的,同样正常退出的话,最好也给一个返回值
                    exit(0);
            }
    }
    ?>

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

    2.通过stream_socket_client 方式

    function sendStream() { 
        $english_format_number = number_format($number, 4, '.', ''); 
      
        echo $english_format_number;  
        exit(); 
        $timeout = 10; 
        $result = array(); 
        $sockets = array(); 
        $convenient_read_block = 8192; 
        $host = "test.local.com"; 
        $sql = "select waybill_id,order_id from xm_waybill where status>40 order by update_time desc limit 1 ";  
        $data = Yii::app()->db->createCommand($sql)->queryAll(); 
        $id = 0; 
      
        foreach ($data as $k => $v) { 
          if ($k % 2 == 0) { 
            $send_data[$k]['body'] = NoticeOrder::getSendData($v['waybill_id']); 
      
          } else { 
            $send_data[$k]['body'] = array($v['order_id'] => array('extra' => 16));  
          }  
          $data = json_encode($send_data[$k]['body']); 
          $s = stream_socket_client($host . ":80", $errno, $errstr, $timeout, STREAM_CLIENT_ASYNC_CONNECT | STREAM_CLIENT_CONNECT); 
          if ($s) {  
            $sockets[$id++] = $s; 
            $http_message = "GET /php/test.php?data=" . $data . " HTTP/1.0
    Host:" . $host . "
    
    ";  
            fwrite($s, $http_message); 
          } else {  
            echo "Stream " . $id . " failed to open correctly."; 
          }  
        } 
      
        while (count($sockets)) { 
      
          $read = $sockets; 
      
          stream_select($read, $w = null, $e = null, $timeout); 
           if (count($read)) {  
            /* stream_select generally shuffles $read, so we need to 
             compute from which socket(s) we're reading. */
            foreach ($read as $r) { 
      
              $id = array_search($r, $sockets); 
              $data = fread($r, $convenient_read_block); 
              if (strlen($data) == 0) { 
                echo "Stream " . $id . " closes at " . date('h:i:s') . ".<br>  "; 
                fclose($r); 
                 unset($sockets[$id]); 
              } else { 
                $result[$id] = $data; 
              } 
            } 
          } else {  
            /* A time-out means that *all* streams have failed 
             to receive a response. */
            echo "Time-out!
    "; 
            break; 
          }  
        }  
        print_r($result); 
      
      }
    
    3、通过多进程代替多线程
    function daemon($func_name,$args,$number){ 
      while(true){ 
        $pid=pcntl_fork(); 
        if($pid==-1){ 
          echo "fork process fail"; 
          exit(); 
        }elseif($pid){//创建的子进程 
      
          static $num=0; 
          $num++; 
          if($num>=$number){ 
            //当进程数量达到一定数量时候,就对子进程进行回收。 
            pcntl_wait($status); 
      
            $num--; 
          }  
        }else{ //为0 则代表是子进程创建的,则直接进入工作状态 
      
          if(function_exists($func_name)){ 
            while (true) { 
              $ppid=posix_getpid(); 
              var_dump($ppid); 
              call_user_func_array($func_name,$args); 
              sleep(2); 
            } 
          }else{ 
            echo "function is not exists"; 
          } 
          exit();   
        } 
      } 
    }  
    function worker($args){  
      //do something 
      
    }  
    daemon('worker',array(1),2); 

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

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

     
    但是这个下载的是 版本3 也就是php 7 才能用的,我们需要使的是 版本2
    然后刷新的页面如下,拖到最底部:

    下一页找到版本2的

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

    下载下来,安装:

    或者,您直接这样下载:

    cd /tools  
       wget https://github.com/krakjoe/pthreads/archive/v2.0.10.zip  
       unzip   v2.0.10.zip  
       cd pthreads-2.0.10  
       /usr/local/php/bin/phpize  
       ./configure --with-php-config=/usr/local/php/bin/php-config    
       make  
       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

    https://www.w3cschool.cn/php/php-thread.html

  • 相关阅读:
    POJ 1300 Open Door
    POJ 2230 Watchcow
    codevs 1028 花店橱窗布置
    codevs 1021 玛丽卡
    codevs 1519 过路费
    codevs 3287 货车运输
    codevs 3305 水果姐逛水果街二
    codevs 1036 商务旅行
    codevs 4605 LCA
    POJ 1330 Nearest Common Ancestors
  • 原文地址:https://www.cnblogs.com/yszr/p/10522534.html
Copyright © 2020-2023  润新知