function a()
    {
        for ($i = 0; $i < 999999; $i++) {
            
        } 
        echo 'test';
        return true;
    }
    function b()
    {
        echo '2';
        return true;
    }
   function cutsBody()
    {
        $this->a();    //这里不等待a函数返回 直接执行b函数
        $this->b();
        return true;
    }
   cutsBody();
执行b函数时不用等待a函数是否返回就执行b函数 知道AJAX可以异步来实现 但我这里用AJAX不方便 有没有其他方法实现?

解决方案 »

  1.   

    写错了~ 
     function cutsBody()
      {
     a(); //这里不等待a函数返回 直接执行b函数
      b();
      return true;
      }
      

  2.   

    首先php没有多进程的概念。
    不会function a 没执行完就去执行function b 。
    这里的话可以采用任务队列来实现。function a()  往数据库添加一个任务,然后服务器端定时跑一个执行任务的脚本。
      

  3.   

    是没有多线程,不是没多进程,能开几个进程是操作系统的事。可以把你的两个函数放到两个不同文件中。
    a.php文件放function a()和function cutsBody()
    b.php文件放function b(),并且直接调用b();将a.php文件中function cutsBody()函数里$this->a();改成用curl请求b.php,这样就是异步的了程序的执行并不会等待curl请求的返回。这相当于开了两个进程。
      

  4.   


    哇,我对3楼很无语~
    直接include不好吗?
      

  5.   

    PHP没多线程很纳闷!只有去找下有没有第三方可利用的~
      

  6.   

    哈哈~ 学过C++都知道 什么是无阻塞 阻塞 命名管道 信号量吧~~  我对PHP也很无语了! 找了一上午最终没能实现 悲剧了~
      

  7.   

    shadowsniper,你的想法很不错,但是我想如果我没记错的话,curl只能等待结果返回才能继续执行,也就说它是同步执行的,不是异步执行的。但是,可以考虑用socket替换curl来实现。
      

  8.   

    curl_init()确实是需要请求的返回,不过curl_multi_init()貌似可以实现异步。楼上说的fsockopen确实是可以做到异步请求的效果。
    下面再来看一个方法,我没搞清楚是为什么,希望大家一起讨论。test.php
    <?php
    echo 123,'<br/>';
    exec("curl 'http://localhost/test2.php' &");
    echo 789;test2.php
    <?php
    sleep(5);
    echo 456,'<br/>';
    在命令行中使用效果。sh-3.2# curl 'http://www.cutefrog.com/test2.php' &
    [1] 3169     //输入上面命令后立刻返回了任务id
    sh-3.2# 456<br/>   //5秒钟后返回了任务的执行结果。
    在shell命令行中,执行的效果与我想象的一样,于是我本以为,也可以拿到php中利用。但实验了一下,却不是我想的那样。sh-3.2# /usr/local/php/bin/php /Users/cutefrog/Sites/test.php 
    123<br/>  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100     8    0     8    0     0      1      0 --:--:--  0:00:05 --:--:--     1
    789sh-3.2# /usr/local/php/bin/php /Users/cutefrog/Sites/test.php 
    123<br/>  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100     8    0     8    0     0      1      0 --:--:--  0:00:05 --:--:--     1
    执行到exec("curl 'http://localhost/test2.php' &");这里时,还是需要等待任务执行结果的返回,而不是拿到建立在后台任务后立刻继续。这点我不太理解。
      

  9.   

    如果用shell_exec()函数会是怎么样呢?
      

  10.   

    我认为嘛, php exec  
    再加个JAVA 计算完成输出
    这里有个前提问题,你的计算量是否有大到要开多线程的必要,
      

  11.   

    搞定了
    test.php
    <?php
    $ch1 = curl_init();
    $ch2 = curl_init();curl_setopt($ch1, CURLOPT_URL, "http://www.cutefrog.com/test2.php");
    curl_setopt($ch1, CURLOPT_TIMEOUT, 28);
    curl_setopt($ch2, CURLOPT_URL, "http://www.cutefrog.com/test3.php");
    curl_setopt($ch2, CURLOPT_HEADER, 0);
    curl_setopt($ch2, CURLOPT_TIMEOUT, 28);$mh = curl_multi_init();curl_multi_add_handle($mh,$ch1);
    curl_multi_add_handle($mh,$ch2);$active = null;
    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);
      }
    }curl_multi_remove_handle($mh, $ch1);
    curl_multi_remove_handle($mh, $ch2);
    curl_multi_close($mh);echo 'done!';test2.php
    <?php
    sleep(1);
    echo 456,'<br/>';test3.php
    <?php
    sleep(5);
    echo 123;test.php相当于一个线程池,由它去发送对test2.php和test3.php的两个请求,test2.php和test3.php这两个请求之间是异步的,并不会相互等待。但他们对于test.php来说是同步的,test.php必须等待所有线程都回收后才会继续执行。
    不过使用这个方法也算是变相模拟了多线程。
      

  12.   

    回14楼:我试了用shell_exec函数,结果和其他的一样,都需要等待5秒。
      

  13.   


    搜索到了这么个贴子:http://topic.csdn.net/t/20050228/10/3811220.html,
    手册里有一句:
    Note:If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends.不知道会不会跟这个有关
      

  14.   

    稍微改了一下,让结果更能说明问题。test.php
    <?php
    $ch1 = curl_init();
    $ch2 = curl_init();curl_setopt($ch1, CURLOPT_URL, "http://www.cutefrog.com/test2.php");
    curl_setopt($ch1, CURLOPT_TIMEOUT, 28);
    curl_setopt($ch2, CURLOPT_URL, "http://www.cutefrog.com/test3.php");
    curl_setopt($ch2, CURLOPT_HEADER, 0);
    curl_setopt($ch2, CURLOPT_TIMEOUT, 28);$mh = curl_multi_init();curl_multi_add_handle($mh,$ch1);
    curl_multi_add_handle($mh,$ch2);$active = null;
    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);
      }
    }curl_multi_remove_handle($mh, $ch1);
    curl_multi_remove_handle($mh, $ch2);
    curl_multi_close($mh);echo 'done!';test2.php
    <?php
    sleep(5);
    echo 123,'<br/>';test3.php
    <?php
    sleep(1);
    echo 456,'<br/>';请看这个例子:
    用test.php先请求test2.php后请求test3.php。
    如果它们是同步执行的话,无论怎么sleep,都应该是先请求test2.php,后请求test3.php,那么最后的结果就应该为:
    123
    456
    done!没错把?
    可是这个例子的最后结果是
    456
    123
    done!我虽然是先调用的test2.php,但由于他sleep了5秒,而test3.php只sleep了1秒。所以test3.php比test2.php先执行完毕。这就证明了,他们之间是异步的,这两个请求是同时发出去的,但不是同时收回的。
      

  15.   

    to 18楼,那个意思是需要将执行的命令的返回结果重定向到其他地方。我考虑到这一点了,所以curl 'http://localhost/test2.php'的后面加了个&,这个跟重定向结果到其他地方是一样的效果。我也试验了重定向,但都没用。curl 'http://localhost/test2.php' > 1.log和nohup curl 'http://localhost/test2.php'。都是需要等待5秒后才能返回。实在不解是为什么。
      

  16.   

    1:fsocket,curl 等模拟
    2:通过fork子进程
      

  17.   


    手册说了,要异步用passthru不过,一般还是想先知道楼主的原始需求,很多时候是有其它办法的...
      

  18.   

    恩 谢谢大家积极回答 我是在用PHP模拟POST下载大文件遇到这个问题的  我的最初想法是服务器返回的文件能够采用多线程的方式分段读取 最后在合并到一个文件中去! 一下我的相关代码 类中抽取的!
    第一部分 模拟POST头
        /**
         +----------------------------------------------------------
         * 函数  sendHeader
         * 发送模拟头信息
         +----------------------------------------------------------
         * @access public
         +----------------------------------------------------------
         * @param Array $params 数据数组
         * @param String $sessid 模拟session     
         +----------------------------------------------------------
         * @return resource
         +----------------------------------------------------------
         */
         public function sendHeader($params = array(), $sessid = '')
        {
            $header = null;
            $body = null;
            $query_str = null;
            if (function_exists('fsockopen')) {
                $fp = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
                if (! $fp) {
                    return false;
                }
                $send_str = "{$this->method} {$this->path}{$this->query} HTTP/1.0\r\n";
                $send_str .= "Host:{$this->host}:{$this->port}\r\n";
                $send_str .= "Accept: */*\r\n";
                $send_str .= "Referer:{$this->referer}\r\n";
                $send_str .= "User-Agent: " . self::SEND_USER_AGENT . "\r\n";
                $send_str .= "Pragma: no-cache\r\n";
                $send_str .= "Cache-Control: no-cache\r\n";
                //如果是POST方法,分析参数
                if ($this->method == 'POST') {
                    //判断参数是否是数组,循环出查询字符串
                    if (is_array($params)) {
                        if (! isset($params[1])) //允许附带POST数据 支持同名
                            $query_str = http_build_query($params);
                        if (isset($params[1]))
                            $query_str = http_build_query($params[0]) . $params[1];
                    } else {
                        $query_str = $params;
                    }
                    $length = strlen($query_str);
                    $send_str .= "Content-Type: application/x-www-form-urlencoded\r\n";
                    $send_str .= "Content-Length: {$length}\r\n";
                }
                //新增伪造session 2011/08/26
                if (! empty($sessid)) {
                    $send_str .= "Cookie: $sessid" . "\n";
                }
                $send_str .= "Connection: Close\r\n\r\n";
                if (strlen($query_str) > 0) {
                    $send_str .= $query_str . "\r\n";
                }
                fputs($fp, $send_str);
                return $fp;
            } else {
                //创建一个用于存放cookie信息的临时文件
                $ch = curl_init($this->url);
                curl_setopt_array($ch, array(
                    CURLOPT_TIMEOUT => $this->timeout, CURLOPT_HEADER => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => self::SEND_USER_AGENT, CURLOPT_REFERER => $this->referer, CURLOPT_COOKIESESSION => true, CURLOPT_COOKIEFILE => $sessid //把之前保存的cookie发送到服务器
                ));
                if ($this->method == 'GET') {
                    curl_setopt($ch, CURLOPT_HTTPGET, true);
                } else {
                    if (is_array($params)) {
                        if (! isset($params[1]))
                            $query_str = http_build_query($params);
                        if (isset($params[1]))
                            $query_str = http_build_query($params[0]) . $params[1];
                    } else {
                        $query_str = $params;
                    }
                    if ($this->method == 'POST')
                        curl_setopt($ch, CURLOPT_POST, true);
                    curl_setopt($ch, CURLOPT_POSTFIELDS, $query_str);
                }
                $fp = curl_exec($ch);
                curl_close($ch);
                if (! $fp) {
                    return false;
                }
                return $fp;
            }
        }
    第二部分 取返回header头
        /**
         * rtnHeader
         * 返回服务器信息
         * @param unknown_type $fp
         */
        public function cutsHeader($fp)
        {
            $header = '';
            do {
                $header .= fread($fp, 1);
            } while (! preg_match("/\r\n\r\n$/", $header));
            $this->header = $header;
            return $header;
        }
    第三部分 就是最重要的 读取文件数据了
        /**
         * rtnHeader
         * 返回服务器信息
         * @param unknown_type $fp
         */
        public function cutsBody($fp)
        {
             $body = '';
            //判断获取类型支持多线程分块读取 
    /*        if (str_exists($this->header, 'application/x-zip-compressed')){
                $dfp = fopen('demo.txt', 'a+');
                while (! feof($fp)) {
                    $body = fgets($fp, 1024);
                    fwrite($dfp, $body);
                }
                fclose($dfp);
                
            }else{*/
               while (! feof($fp)) {
                    $body .= fgets($fp, 1024);
                }
          //  }
            return $body;
        }
    就是这里 看有没有其他方法不顺序读取$fp资源 能够分段读取 最后在组合文件!这是我最初的想法~
      

  19.   

    如果是ftp下载,php直接提供了non-blocking的函数,注意最后一个参数可以用于续传(你需要的部分下载)
    http://ca2.php.net/manual/en/function.ftp-nb-fget.php如果是http下载,curl或socket续传的方法可以参考这里:
    http://www.ankur.com/blog/106/php/resume-http-downloads-php-curl-fsockopen/
    至于non-blocking,这个php函数可以用于socket,
    http://ca2.php.net/manual/en/function.stream-set-blocking.php
    curl应该也可以non-block,但一时没找到合适的资料,你有兴趣可以找找.