Проблема многопоточности php

Я пишу задание php cron, которое читает тысячи фидов / веб-страниц, используя curl и сохраняет содержимое в базе данных. Как ограничить количество потоков, скажем, 6? т. е. хотя мне нужно сканировать тысячи фидов / веб-страниц, я хочу, чтобы в любое время было всего 6 завитущих потоков, чтобы мой сервер и сеть не увязли. Я мог бы сделать это легко в Java, используя wait, notify, notifyвсе методы Object. Должен ли я строить собственный семафор или php предоставляет какие-либо встроенные функции?

Solutions Collecting From Web of "Проблема многопоточности php"

Прежде всего, PHP не имеет потоков, но имеет контроль процесса: http://php.net/manual/en/book.pcntl.php

Я создал класс вокруг этих функций, чтобы помочь в моих требованиях к мультипроцессу.

Я в подобной ситуации. Я сохраняю журнал процессов, которые начинаются с cron и их состояния. Я проверяю их из связанной работы cron.

EDIT (подробнее):

В моем проекте я регистрирую все ключевые изменения в базе данных. Затем действия могут быть предприняты, если изменения соответствуют критерию действия. Поэтому то, что я делаю, отличается от вас. Однако есть некоторые сходства.

Когда я развиваю новый процесс, я ввожу его pid в таблицу DB. Затем в следующий раз, когда начнется задание cron, часть того, что он делает, это проверить, правильно ли обработаны процессы, а затем отметить действие, завершенное в этой таблице DB.

Вы не даете много подробностей о своем проекте. Поэтому я просто выброшу предложение:

  • В таблице DB содержатся URL-адреса ресурсов, которые вы хотите загрузить.
  • В другой таблице содержатся текущие процессы.
  • Задача cron, которая запускается каждый час, будет проходить через таблицу и загружать ресурс и хранить его в БД. Однако сначала он проверяет таблицу pid для полных / мертвых / запущенных процессов и действует соответственно. Здесь вы можете ограничить свои процессы до 6.

В зависимости от размера вашего проекта это может показаться чрезмерным. Тем не менее, я думал об этом в течение долгого времени, и я хочу отслеживать все эти разветвленные процессы. Викинг может быть рискованным бизнесом и может привести к перегрузке системных ресурсов – говоря по опыту;)

Мне было бы интересно услышать и другие приемы.

Из моего ответа на PHP с помощью proc_open, чтобы он не дождался, когда скрипт откроется (запустится), чтобы закончить?

Некоторые из моего кода, когда я играл с proc_open
У меня были проблемы с proc_close (от 10 до 30 секунд), поэтому я просто убил процесс, используя команду linux kill

Curl иногда freezez для меня на разных серверах (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 означает, что вы пятый ребенок и ему разрешено работать 60 секунд

Если приведенный выше код не запускается, дайте мне знать, я отправлю его с помощью pastebin или что-то еще …