前の 2 つの質問の助けを借りて、製品情報をデータベースにフィードする HTML スクレーパーが動作するようになりました。私が今やろうとしているのは、スクレーパーをpcntl_fork
.
php5-cli スクリプトを 10 個の個別のチャンクに分割すると、全体のランタイムが大幅に改善されるため、I/O や CPU に縛られているわけではなく、スクレイピング関数の線形的な性質によって制限されているだけであることがわかります。
複数のソースからまとめたコードを使用して、次の動作テストを行いました。
<?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 が含まれているとします。たとえば、配列に 1,000 個の製品 URL が含まれている場合、このコードは 1,000 個の子プロセスを生成しますか? その場合、プロセスの量を 10 に制限する最善の方法は何ですか。例として 1,000 の 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[] をマスター/親プロセスでのみ構築し、それを子プロセスに供給する方法です。現在、私が試したことはすべて、子プロセスでループを引き起こします。つまり、私の hrefsArray はマスターと後続の各子プロセスで構築されます。
私はこれについて完全に間違っていると確信しているので、正しい方向への一般的なナッジだけを大いに感謝します.