С помощью двух предыдущих вопросов у меня теперь есть рабочий HTML-скребок, который подает информацию о продукте в базу данных. То, что я сейчас пытаюсь сделать, - это улучшить эффективность, обернув свой мозг, заставив мой скребок работать с pcntl_fork
.
Если я разделю свой скрипт php5-cli на 10 отдельных кусков, я значительно увеличу общее время выполнения, так что я знаю, что я не привязан ни к вводу / выводу, ни к процессору, а просто ограничен линейным характером моих функций очистки.
Используя код, который я собрал из нескольких источников, у меня есть этот рабочий тест:
<?php
libxml_use_internal_errors(true);
ini_set('max_execution_time', 0);
ini_set('max_input_time', 0);
set_time_limit(0);
$hrefArray = array("http://slashdot.org", "http://slashdot.org", "http://slashdot.org", "http://slashdot.org");
function doDomStuff($singleHref,$childPid) {
$html = new DOMDocument();
$html->loadHtmlFile($singleHref);
$xPath = new DOMXPath($html);
$domQuery = '//div[@id="slogan"]/h2';
$domReturn = $xPath->query($domQuery);
foreach($domReturn as $return) {
$slogan = $return->nodeValue;
echo "Child PID #" . $childPid . " says: " . $slogan . "\n";
}
}
$pids = array();
foreach ($hrefArray as $singleHref) {
$pid = pcntl_fork();
if ($pid == -1) {
die("Couldn't fork, error!");
} elseif ($pid > 0) {
// We are the parent
$pids[] = $pid;
} else {
// We are the child
$childPid = posix_getpid();
doDomStuff($singleHref,$childPid);
exit(0);
}
}
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
}
// Clear the libxml buffer so it doesn't fill up
libxml_clear_errors();
Что поднимает следующие вопросы:
1) Учитывая, что мой hrefArray содержит 4 URL-адреса - если бы массив должен был содержать, скажем, 1000 URL-адресов продуктов, этот код породил бы 1000 дочерних процессов? Если это так, то каков наилучший способ ограничить количество процессов, скажем, до 10, и, опять же, 1000 URL в качестве примера, разделить дочернюю рабочую нагрузку до 100 продуктов на одного ребенка (10 x 100).
2) Я узнал, что pcntl_fork создает копию процесса и всех переменных, классов и т. Д. Я хотел бы заменить мою переменную hrefArray на запрос DOMDocument, который строит список продуктов для очистки, и затем передает их дочерним процессам для выполнения обработки - таким образом, нагрузка распределяется на 10 дочерних процессов.
Мой мозг говорит, что мне нужно сделать что-то вроде следующего (очевидно, это не работает, поэтому не запускайте его):
<?php
libxml_use_internal_errors(true);
ini_set('max_execution_time', 0);
ini_set('max_input_time', 0);
set_time_limit(0);
$maxChildWorkers = 10;
$html = new DOMDocument();
$html->loadHtmlFile('http://xxxx');
$xPath = new DOMXPath($html);
$domQuery = '//div[@id=productDetail]/a';
$domReturn = $xPath->query($domQuery);
$hrefsArray[] = $domReturn->getAttribute('href');
function doDomStuff($singleHref) {
// Do stuff here with each product
}
// To figure out: Split href array into $maxChilderWorks # of workArray1, workArray2 ... workArray10.
$pids = array();
foreach ($workArray(1,2,3 ... 10) as $singleHref) {
$pid = pcntl_fork();
if ($pid == -1) {
die("Couldn't fork, error!");
} elseif ($pid > 0) {
// We are the parent
$pids[] = $pid;
} else {
// We are the child
$childPid = posix_getpid();
doDomStuff($singleHref);
exit(0);
}
}
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
}
// Clear the libxml buffer so it doesn't fill up
libxml_clear_errors();
Но я не могу понять, как построить мой hrefsArray [] только в процессе master / parent и передать его дочернему процессу. В настоящее время все, что я пробовал, вызывает циклы в дочерних процессах. То есть Мой hrefsArray встроен в мастер и в каждый последующий дочерний процесс.
Я уверен, что я все делаю совершенно неправильно, поэтому буду очень признателен, если просто подтолкнете в правильном направлении.