欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  php教程

php curl_multi_select 死循环原因及相应处理办法

程序员文章站 2022-03-09 18:30:02
...

现象 在系统更新以后,相应的php也升级到了新的版本.在运行了自己的代码之后,发现程序直接卡死不动了.在经过一阵排查之后,发现其卡在了非常诡异的地方 //use select to get response //proceed select until all handle response //can refer php.net page, c

现象

在系统更新以后,相应的php也升级到了新的版本.在运行了自己的代码之后,发现程序直接卡死不动了.在经过一阵排查之后,发现其卡在了非常诡异的地方

 //use select to get response
 //proceed select until all handle response
 //can refer php.net page, curl_multi_select() api
 while ($this->active && $mrc == CURLM_OK) 
 {   
     if (curl_multi_select($this->mh) != -1) 
     {   
         do {
             $mrc = curl_multi_exec($this->mh, $this->active);
             if ($mrc == CURLM_OK)
             {   
                 while($info = curl_multi_info_read($this->mh))
                 {   
                     $this->process($info);
                 }        
             }   
         } while ($mrc == CURLM_CALL_MULTI_PERFORM);
     }   
 }

另外可以注意到,CPU的使用率一直100%,说明我们的程序卡死了.

而经过一阵debug,发现程序运行到curl_multi_select之后,一直返回-1,然后就不断进入循环,卡死了.

原因探究

原来在10.8.5的时候,代码是能运行的,而且在linux中运行也很正常,因此,结果之后可能是php或者是相应依赖随着系统变化引起的问题.观察命名也能知道curl_multi_select其背后是基于libcurl进行实现的.而两个系统的libcurl版本也确实不同.

通过查看curl_multi_exec,有个用户的回复引起了注意.

Alex Palmer 10 months ago
On php 5.3.18+ be aware that curl_multi_select() may return -1 forever until you call curl_multi_exec(). See https://bugs.php.net/bug.php?id=63411 for more information.

查看bug列表,发现了原作者的回答:

[2012-11-03 03:42 UTC] pierrick@php.net
I’m not sure we really want to wait 1 second for nothing in this specific case. Furthermore, as mentioned in my commit message, when libcurl returns -1 in max_fd after calling curl_multi_fdset, it is because libcurl currently does something that isn’t possible for your application to monitor with a socket and unfortunately you can then not know exactly when the current action is completed using select().
I would personally keep the current behaviour.

所以显然是curl_multi_select一直返回了-1,导致了程序进入了死循环,卡死掉了.而这个是进入了php5.3.8以后,做出的改变.

正确的curl_multi_select写法

那在这样的behaviour下,该如何编写curl_multi_select呢.

经过一番研究,终于找到了合适的写法.关键在于在while循环中要执行curl_multi_exec,直到处理完毕再进入select.

实现代码:

    while ($this->active && $mrc == CURLM_OK) 
    {   
        while (curl_multi_exec($this->mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
       if (curl_multi_select($this->mh) != -1) 
       {   
           do {
               $mrc = curl_multi_exec($this->mh, $this->active);
               if ($mrc == CURLM_OK)
               {   
                   while($info = curl_multi_info_read($this->mh))
                   {   
                       $this->process($info);
                   }        
               }   
           } while ($mrc == CURLM_CALL_MULTI_PERFORM);
       }   
    } 

影响的php版本

这个我没有深入探究,理论上这个是和curl以及php版本有关系.

从其他使用者反馈的有:

  • 5.4.7
  • 5.4.8
  • 5.3.17
  • 5.4.7

Related Posts:

  • Python初探–Socket Server
  • *源码解析
  • About Me
  • listen()详解
  • MAC…