2010-08-25 86 views
0

我正在写一个php cron作业,使用curl读取数以千计的提要/网页并将内容存储在数据库中。如何限制线程的数量,比如说6?即使我需要扫描数以千计的提要/网页,但我只想在任何时候只有6个卷曲线程处于活动状态,这样我的服务器和网络就不会陷入困境。我可以在Java中使用wait,notify,notifyall方法轻松地完成Object。我应该建立自己的信号量还是php提供任何内置函数?php多线程问题

+0

PHP是不是线程。除非您使用curl_multi *系列函数,否则您的curl请求将会阻塞,直到完成为止。 – meagar 2010-08-25 00:44:06

+0

我最终使用了http://github.com/LionsAd/rolling-curl库来满足我的需求。没有进程,没有线程。 – Zero 2010-08-25 15:10:14

回答

2

首先,PHP没有线程,但它确实有过程控制: http://php.net/manual/en/book.pcntl.php

我已经建立了围绕这些函数的类来帮助我的多工艺要求。

我处于类似的情况。我正在记录从cron开始的进程及其状态。我正在从一个相关的cron工作中检查他们。

EDIT(详细信息):

在我的项目我都记录到数据库的关键变化。如果变更符合行动标准,则可采取行动。所以我正在做的与你不同。但是,也有一些相似之处。

当我分叉一个新的进程,我输入它的PID在数据库表。然后下一次cron作业开始时,它所做的一部分工作就是检查进程是否已正确完成,然后在该数据库表中将该作业标记为已完成。

你不会提供关于你的项目的很多细节。所以我只是抛出一个建议:

  • 数据库表包含您要下载的资源的URL。
  • 另一张表包含正在运行的进程的pid。
  • 每小时运行一个cron作业将通过该表并下载资源并将其存储在数据库中。但是,首先检查pid表是否有完整/死/正在运行的进程,并相应地执行。在这里,您可以限制您的流程为6.

根据您的项目大小,这可能看起来像是过度杀人。不过,我已经考虑了很长时间了,我想跟踪所有这些分叉进程。分叉可能是有风险的业务,并且可能导致系统资源过载 - 从经验上讲);

我很想听听其他技术。

+0

感谢您的快速回答。如何在6个进程中同步计数器?两个进程不应该尝试同时更新计数器。 – Zero 2010-08-25 01:10:36

+0

我已经给答案添加了一些细节。我不知道你的项目结构如何,所以我不能确定这是否适合你,但我希望它有帮助。 – 2010-08-25 03:29:24

0

从我的答复在PHP using proc_open so that it doesn't wait for the script it opens (runs) to finish?

我的一些代码,当我与proc_open
发挥各地我曾与proc_close(10〜30秒),所以我只是用杀进程的问题linux命令杀人

curl有时候会在各种服务器(ubuntu,centos)上冻结我,但并不是所有的服务器上,所以我杀掉任何需要40秒的“子”进程,因为通常脚本最多需要10秒钟,而是重做工作,而不是等待一分钟左右,因为卷曲不会冻结。



$options=array(); 
$option['sleep-after-destroy']=0; 
$option['sleep-after-create']=0; 
$option['age-max']=40; 
$option['dir-run']=dirname(__FILE__); 
$option['step-sleep']=1; 
$option['workers-max']=6; 
$option['destroy-forcefull']=1; 

$workers=array(); 

function endAWorker($i,$cansleep=true) { 
     global $workers; 
     global $option; 
     global $child_time_limit; 
     if(isset($workers[$i])) { 
       @doE('Ending worker [['.$i.']]'."\n"); 
       if($option['destroy-forcefull']==1) { 
         $x=exec('ps x | grep "php check_working_child.php '.$i.' '.$child_time_limit.'" | grep -v "grep" | grep -v "sh -c"'); 
         echo 'pscomm> '.$x."\n"; 
         $x=explode(' ',trim(str_replace("\t",' ',$x))); 
         //print_r($x); 
         if(is_numeric($x[0])) { 
           $c='kill -9 '.$x[0]; 
           echo 'killcommand> '.$c."\n"; 
           $x=exec($c); 
         } 
       } 
       @proc_close($workers[$i]['link']); 
       unset($workers[$i]); 
     } 
     if($cansleep==true) { 
       sleep($option['sleep-after-destroy']); 
     } 
} 

function startAWorker($i) { 
     global $workers; 
     global $option; 
     global $child_time_limit; 

     $runcommand='php check_working_child.php '.$i.' '.$child_time_limit.' > check_working_child_logs/'.$i.'.normal.log'; 
     doE('Starting [['.$i.']]: '.$runcommand."\n"); 
     $workers[$i]=array(
       'desc' => array(
         0 => array("pipe", "r"), 
         1 => array("pipe", "w"), 
         2 => array("file", 'check_working_child_logs/'.$i.'.error.log', "a") 
         ), 
       'pipes'     => null, 
       'link'     => null, 
       'start-time' => mktime() 
       ); 
     $workers[$i]['link']=proc_open(
       $runcommand, 
       $workers[$i]['desc'], 
       $workers[$i]['pipes'], 
       $option['dir-run'] 
       ); 
     sleep($option['sleep-after-create']); 
} 

function checkAWorker($i) { 
     global $workers; 
     global $option; 
     $temp=proc_get_status($workers[$i]['link']); 
     if($temp['running']===false) { 
       doE('Worker [['.$i.']] finished'."\n"); 
       if(is_file('check_working_child_logs/'.$i.'.normal.log') && filesize('check_working_child_logs/'.$i.'.normal.log')>0) { 
         doE('--------'."\n"); 
         echo file_get_contents('check_working_child_logs/'.$i.'.normal.log'); 
         doE('-------'."\n"); 
       } 
       endAWorker($i); 
     } else { 
       if($option['age-max']>0) { 
         if($workers[$i]['start-time']+$option['age-max']$v) { 
       endAWorker($i,false); 
     } 
     @doE('Done killing workers.'."\n"); 
} 

register_shutdown_function('endAllWorkers'); 

while(1) { 
     $step++; 
     foreach($workers as $index=>$v) { 
       checkAWorker($index); 
     } 
     if(count($workers)==$option['workers-max']) { 
     } elseif(count($workers)$option['workers-max']) { 
       $wl=array_keys($workers); 
       $wl=array_pop($wl); 
       doE('Killing worker [['.$wl.']]'); 
       endAWorker($wl[0]); 
     } 
} 

并创建一个名为“check_working_child.php”来完成所有的工作文件,第一个参数将是实例号,第二个时间限制 php check_working_child.php 5 60 意味着你是第5子和被允许运行60秒

如果上面的代码不运行让我知道,我会使用pastebin或其他东西发布它...