スパイダーページに同時に Web スパイダーを書きました。スパイダーが見つけたリンクごとに、プロセスを最初からやり直す新しい子をフォークしたいと考えています。
ターゲット サーバーに負荷をかけたくないので、すべてのオブジェクトがアクセスできる静的配列を作成しました。各子は自分の PID を配列に追加できます。親または子のいずれかが配列をチェックして、$maxChildren が満たされているかどうかを確認する必要があります。満たされている場合は、いずれかの子が終了するまで辛抱強く待ちます。
ご覧のとおり、$maxChildren を 3 に設定しています。いつでも 3 つの同時プロセスが見られると予想しています。しかし、そうではありません。Linux の top コマンドは、常に 12 から 30 のプロセスを表示します。並行プログラミングでは、同時処理数をどのように調整できますか? 私のロジックは現在、Apache が最大の子を処理する方法に着想を得ていますが、それがどのように機能するかは正確にはわかりません。
回答の1つで指摘されているように、静的変数にグローバルにアクセスすると、競合状態の問題が発生します。これに対処するために、$children 配列はプロセスの一意の $PID をキーとその値の両方として取得し、それによって一意の値を作成します。私の考えでは、オブジェクトは 1 つの $children[$pid] 値しか扱えないので、ロックは必要ありません。これは真実ではありませんか?ある時点で 2 つのプロセスが同じ値を設定解除または追加しようとする可能性はありますか?
private static $children = array();
private $maxChildren = 3;
public function concurrentSpider($url) {
// STEP 1:
// Download the $url
$pageData = http_get($url, $ref = '');
if (!$this->checkIfSaved($url)) {
$this->save_link_to_db($url, $pageData);
}
// STEP 2:
// extract all hyperlinks from this url's page data
$linksOnThisPage = $this->harvest_links($url, $pageData);
// STEP 3:
// Check the links array from STEP 2 to see if this page has
// already been saved or is excluded because of any other
// logic from the excluded_link() function
$filteredLinks = $this->filterLinks($linksOnThisPage);
shuffle($filteredLinks);
// STEP 4: loop through each of the links and
// repeat the process
foreach ($filteredLinks as $filteredLink) {
$pid = pcntl_fork();
switch ($pid) {
case -1:
print "Could not fork!\n";
exit(1);
case 0:
if ($this->checkIfSaved($filteredLink)) {
exit();
}
//$pid = getmypid();
print "In child with PID: " . getmypid() . " processing $filteredLink \n";
$var[$pid]->concurrentSpider($filteredLink);
sleep(2);
exit(1);
default:
// Add an element to the children array
self::$children[$pid] = $pid;
// If the maximum number of children has been
// achieved, wait until one or more return
// before continuing.
while (count(self::$children) >= $this->maxChildren) {
//print count(self::$children) . " children \n";
$pid = pcntl_waitpid(-1, $status);
unset(self::$children[$pid]);
}
}
}
}
これはPHPで書かれています。pcntl_waitpid
-1 の引数を持つ関数は、親に関係なく子が完了するのを待機することを知っています ( http://php.net/manual/en/function.pcntl-waitpid.php )。
ロジックの何が問題なの$maxChildren
ですか?プロセスのみが同時に実行されるように修正するにはどうすればよいですか? 提案があれば、一般的なロジックを改善することにもオープンです。