PHP - 使用multi_curl并行处理一个好主意?

时间:2012-09-18 14:47:39

标签: php multithreading curl parallel-processing

我需要在PHP中进行并行处理,但PHP不支持它而不安装扩展,所以我使用multi_curl来实现这一点。

main.php - 构建一个url数组,这些url都是process.php,具有不同的$ _GET参数。然后使用multi_curl执行它们。

process.php - 每个线程的处理逻辑。

我只想知道这是否是一种可行的做事方式。这是迟钝的吗?它会导致很多开销吗?有更明智的方法吗?感谢。

4 个答案:

答案 0 :(得分:1)

https://github.com/krakjoe/pthreads

PHP的线程......

享受......

要在unix中安装,您需要一个PHP的线程安全版本。大多数发行版都没有打包这个版本,所以你必须自己构建它。

如何执行此操作的快速说明将是:

cd /usr/src
wget  http://php.net/get/php-5.3.17.tar.bz2/from/us.php.net/mirror
tar -xf php-5.3.17.tar.bz2
cd php-5.3.17/ext
wget https://github.com/krakjoe/pthreads/tarball/master -O pthreads.tar.gz
tar -xf pthreads.tar.gz
mv krakjoe-pthreads* pthreads
cd ../
./buildconf --force
./configure --enable-maintainer-zts --enable-pthreads --prefix=/usr
make
make install

我从那开始,构建一个带有私有位置的隔离副本--prefix,比如--prefix = / home / mydir,或者某些发行版有一个/ usr / src / debug这是一个很好的地方诸如此类的事情。你显然想添加--with-mysql之类的东西,但你怎么做取决于你的系统(提示,你可以使用php -i | grep configure> factory.config来保存你当前的php安装配置行并且基于你的自定义构建,知道它抱怨的任何库都不可用是apt-get | yum install away)。

答案 1 :(得分:0)

当然,这是一种可行的做事方式,这就是功能存在的原因。

与往常一样,魔鬼在于细节。多个并发请求将与其他进程竞争并消耗服务器资源;你需要调节并发度。

答案 2 :(得分:0)

考虑到PHP不支持任何合理的多处理,multi_curl似乎是一个很好的解决方案!

答案 3 :(得分:0)

如果你在网络服务器上运行PHP(并且multi_curl可能不可用),一种方式(没有库)使它并行运行脚本就是打开socket到localhost:80并手动让webserver运行你想要的脚本。它们将使用服务器多线程并行运行。然后在循环中收集所有结果,当所有结果都完成时(或在你选择的超时后),你继续。

这是从脚本中获取的一段代码,用于检索网页上引用的所有图像的大小。

get_img_size.php脚本检索一个图像的大小和信息。

$ sockets []是一个数组,为每个要测试的图像保留一个套接字。

        foreach($metaItems['items'] as $uCnt=>$uVal) {
            $metaItem=ContentLoader::splitOneNew($metaItems,$uCnt);
            $AnImage=$metaItem['url'];

            $sockets[$AnImage] = fsockopen($_SERVER['HTTP_HOST'], 80, $errno, $errstr, 30);
            if(!$sockets[$AnImage]) {
                echo "$errstr ($errno)<br />\n";
            } else {
                $pathToRetriever=dirname($_SERVER['PHP_SELF']).'/tools/get_img_size.php?url='.rawurlencode($AnImage);
                // echo('<div>META Retrieving '.$pathToRetriever.' on server '.$_SERVER['HTTP_HOST'].'</div>');
                $out = "GET $pathToRetriever HTTP/1.1\r\n";
                $out .= "Host: ".$_SERVER['HTTP_HOST']."\r\n";
                $out .= "Connection: Close\r\n\r\n";
                // echo($out);
                fwrite($sockets[$AnImage], $out);
                fflush($sockets[$AnImage]);
                // echo("<div>Socket open for $AnImage...</div>");
                // flush();
            }
        }
    }  else $FoundImagePaths2[]=$metaItems; // ALL of them urls belongs to us

在此之后,您可以在“线程”继续工作的同时开展自己的业务,然后在循环中继续阅读所有$ socket []并测试EOF。在示例中,稍后在代码中(每个$ AnImage的循环):

            if(isset($sockets[$AnImage])) {
                if(feof($sockets[$AnImage])) {
                    if(!isset($sizes[$AnImage])) $sizes[$AnImage]='';
                    $sizes[$AnImage].=fgets($sockets[$AnImage], 4096);

                    // echo("<div>HTML $AnImage DONE.</div>");
                    // echo("<div>[ ".$sizes[$AnImage]." ]</div>");
                    // flush();
                    fclose($sockets[$AnImage]);
                    unset($sockets[$AnImage]);

                    $mysizes=ContentLoader::cleanResponse($sizes[$AnImage]);

                    // echo($sizes[$AnImage]." ");
                    // echo(ContentLoader::cleanResponse($sizes[$AnImage]));

                    if(!is_array($mysizes)) {continue;}

                    if($mysizes[0]>64 && $mysizes[1]>64 && ($mysizes[0]>128 || $mysizes[1]>128))
                        $FoundImagePaths2[]=array('kind'=>'image','url'=>$AnImage,'ext'=>$ext,'width'=>$mysizes[0],'height'=>$mysizes[1],'mime'=>$mysizes['mime']);

在内存和进程方面以及在速度方面效率不高,但如果单个图像需要几秒钟,则具有20多个图像的整个页面需要相同的几秒钟来测试它们。毕竟,它与PHP并行。