ホームページ >バックエンド開発 >PHPチュートリアル >PHPマルチプロセス(4): 内部マルチプロセス

PHPマルチプロセス(4): 内部マルチプロセス

WBOY
WBOYオリジナル
2016-06-20 12:32:30929ブラウズ

上記の一連のチュートリアル:

PHP マルチプロセス プログラミング (1)

PHP マルチプロセス プログラミング (2) パイプライン通信

PHP マルチプロセスプログラミング (3) マルチプロセス Web クローリングのデモ

次に、unix サーバーのみに対応したマルチプロセスについて説明します。 window と unix の両方 (ここでは一般的に指します。以下のカールは実際には IO 多重化によって実装されています)。

拡張機能を使用してマルチスレッドを実装する典型的な例は、CURL がマルチスレッド Web ページ クローリングをサポートしていることです。

この部分は抽象的すぎるため、最初に複数の Web ページ コンテンツを並行してクロールするための CURL のパッケージ化クラスを提供します。このクラスは実際には非常に実用的です。

これらの関数の内部実装の詳細な分析については、次のチュートリアルで説明します。

このクラスはよく理解できないかもしれませんが、PHP CURL の公式ホームページに多くのエラー例が掲載されているので、その内部機構

を説明すると理解できるようになります。

最初にコードを見てください:

 class Http_MultiRequest{    //要并行抓取的url 列表    private $urls = array();    //curl 的选项    private $options;    //构造函数    function __construct($options = array())    {        $this->setOptions($options);    }    //设置url 列表    function setUrls($urls)    {        $this->urls = $urls;        return $this;    }    //设置选项    function setOptions($options)    {        $options[CURLOPT_RETURNTRANSFER] = 1;        if (isset($options['HTTP_POST']))         {            curl_setopt($ch, CURLOPT_POST, 1);            curl_setopt($ch, CURLOPT_POSTFIELDS, $options['HTTP_POST']);            unset($options['HTTP_POST']);        }        if (!isset($options[CURLOPT_USERAGENT]))         {            $options[CURLOPT_USERAGENT] = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)';        }        if (!isset($options[CURLOPT_FOLLOWLOCATION]))         {            $options[CURLOPT_FOLLOWLOCATION] = 1;        }        if (!isset($options[CURLOPT_HEADER]))        {            $options[CURLOPT_HEADER] = 0;        }        $this->options = $options;    }    //并行抓取所有的内容    function exec()    {        if(empty($this->urls) || !is_array($this->urls))        {            return false;        }        $curl = $data = array();        $mh = curl_multi_init();        foreach($this->urls as $k => $v)        {            $curl[$k] = $this->addHandle($mh, $v);        }        $this->execMulitHandle($mh);        foreach($this->urls as $k => $v)        {            $data[$k] = curl_multi_getcontent($curl[$k]);            curl_multi_remove_handle($mh, $curl[$k]);        }        curl_multi_close($mh);        return $data;    }    //只抓取一个网页的内容。    function execOne($url)    {        if (empty($url)) {            return false;        }        $ch = curl_init($url);        $this->setOneOption($ch);        $content = curl_exec($ch);        curl_close($ch);        return $content;    }    //内部函数,设置某个handle 的选项    private function setOneOption($ch)    {        curl_setopt_array($ch, $this->options);    }    //添加一个新的并行抓取 handle    private function addHandle($mh, $url)    {        $ch = curl_init($url);        $this->setOneOption($ch);        curl_multi_add_handle($mh, $ch);        return $ch;    }    //并行执行(这样的写法是一个常见的错误,我这里还是采用这样的写法,这个写法    //下载一个小文件都可能导致cup占用100%, 并且,这个循环会运行10万次以上    //这是一个典型的不懂原理产生的错误。这个错误在PHP官方的文档上都相当的常见。)    private function execMulitHandle2($mh)    {        $i = 0;        $running = null;        do {            curl_multi_exec($mh, $running);            $i++;        } while ($running > 0);        //var_dump($i);    }    //应该用这样的写法    private function execMulitHandle($mh)    {        $i = 0;        do {$mrc = curl_multi_exec($mh,$active); $i++;} while ($mrc == CURLM_CALL_MULTI_PERFORM);        while ($active && $mrc == CURLM_OK)         {            if (curl_multi_select($mh) != -1)            {                do {$mrc = curl_multi_exec($mh, $active); $i++;} while ($mrc == CURLM_CALL_MULTI_PERFORM);            }            $i++;        }        //var_dump($i);    }}

最も多くのコメントを持つ最後の関数を見てください。プログラムは完全に正常であるため、通常のデバッグではこのエラーを見つけるのは簡単ではないかもしれません。ただし、運用サーバーでは、すぐにクラッシュの影響が発生します。

これができない理由の説明は、C 言語の内部実装の観点から分析する必要があります。この部分は次のチュートリアル (PHP 高度なプログラミング – シングルスレッドの並列 Web フェッチ) に移動されます。ただし、この原理は C 言語ではなく、PHP の

クラスで表現されています。実際、これまでに費やした 4 つのチュートリアルの実装は非常に簡単ですが、多大な労力がかかりました。 . マルチスレッドWebページクローリング機能を実装しました。純粋な PHP の実装では、より良い実装を実現するにはバックグラウンド サービスを使用するしかありませんが、オペレーティング システムのインターフェイス言語である C 言語を使用すると、当然のことながら、この実装はよりシンプルで、より柔軟で、より効率的になります。

同時に複数の Web ページをクロールするだけで簡単ですが、実際には下位レベルで多くの処理が必要になります。途中で僧侶になってしまった多くの PHP プログラマーにとって、複数の Web ページについて話したくないかもしれません。オペレーティング システムに関して言えば、簡単に言うと、複数の「プログラム」を並行して実行することを意味します。ただし、多くの場合、マルチスレッドが不可欠です。たとえば、より高速なクローラーを作成したい場合、労力が無駄になることがよくあります。ただし、PHP プログラマは、この拡張機能の CURL に感謝する必要があります。これにより、中規模のクローラを作成するためにあまり熟練していない Python を使用する必要がなくなりました。この内部マルチスレッドがあれば十分です。

最後に、上記のクラスのテスト例:

$urls = array("http://baidu.com", "http://baidu.com", "http://baidu.com", "http://baidu.com", "http://baidu.com", "http://baidu.com", "http://www.google.com", "http://www.sina.com.cn", );$m = new Http_MultiRequest();$t = microtime(true);$m->setUrls($urls);//parallel fetch(并行抓取):$data = $m->exec();$parallel_time = microtime(true) - $t;echo $parallel_time . "\n";$t = microtime(true);//serial fetch(串行抓取):foreach ($urls as $url){    $data[] = $m->execOne($url);}$serial_time = microtime(true) - $t;echo $serial_time . "\n";
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。