2010-08-25 102 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或其他東西發佈它...