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

PHP-使用multi_curl进行并行处理是一个好主意吗?,php,multithreading,curl,parallel-processing,Php,Multithreading,Curl,Parallel Processing,我需要在PHP中进行并行处理,但是如果不安装扩展,PHP就不支持并行处理,所以我使用multi_curl来实现这一点 main.php-构建一个URL数组,这些URL都是process.php,具有不同的$\u GET参数。然后使用multi_curl执行它们 process.php-每个线程的处理逻辑 我只是想知道这是否是一种可行的做事方式。这是弱智吗?这会造成很多开销吗?有没有更明智的方法?谢谢。当然,一般来说,这是一种可行的方式,这就是功能存在的原因 和往常一样,细节才是魔鬼。多个并发请求

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

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

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


我只是想知道这是否是一种可行的做事方式。这是弱智吗?这会造成很多开销吗?有没有更明智的方法?谢谢。

当然,一般来说,这是一种可行的方式,这就是功能存在的原因


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

请记住,PHP不支持通过任何合理的方式进行多处理,对于您的情况,multi_curl似乎是一个很好的解决方案

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=/home/mydir,或者一些发行版有一个/usr/src/debug,这是一个很好的地方。很明显,您需要添加——使用mysql等,但如何添加取决于您的系统(提示,您可以使用php-i | grep configure>factory.config来保存当前的php安装配置行,并在您的自定义构建基础上,知道它抱怨的任何库都不可用,这是一个很好的| yum install away)

如果您在Web服务器上运行PHP(可能无法使用multi_curl),使其并行运行脚本的一种方法(没有库)是打开localhost:80的套接字并手动使Web服务器运行所需的脚本。它们将使用服务器多线程并行运行。然后在一个循环中收集所有结果,当所有结果都完成时(或在您选择的超时之后),继续

这是一段取自脚本的代码,该脚本检索网页上引用的所有图像的大小

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
foreach($metaItems['items']作为$uCnt=>$uVal){
$metaItem=ContentLoader::splitOneNew($metaItems,$uCnt);
$AnImage=$metaItem['url'];
$sockets[$AnImage]=fsockopen($\服务器['HTTP\主机'],80,$errno,$errstr,30);
如果(!$sockets[$AnImage]){
回显“$errstr($errno)
\n”; }否则{ $pathToRetriever=dirname($\u SERVER['PHP\u SELF'])。/tools/get\u img\u size.PHP?url='.rawurlencode($AnImage); //echo('META-Retrieving'.$pathToRetriever.'在服务器'.$'上'.$'服务器['HTTP\u主机'.'); $out=“GET$pathToRetriever HTTP/1.1\r\n”; $out.=“主机:”.$\u服务器['HTTP\U主机]。“\r\n”; $out.=“连接:关闭\r\n\r\n”; //echo($out); fwrite($sockets[$AnImage],$out); fflush($sockets[$AnImage]); //echo(“为$AnImage打开的插座…”); //冲洗(); } } }else$FoundImagePaths2[]=$metaItems;//所有这些URL都属于我们
在此之后,您可以在“线程”继续工作的同时完成自己的业务,然后,在一个循环中,继续读取所有$sockets[]并测试EOF。在本例中,代码后面的很多部分(每个$AnImage都有一个循环):

if(isset($sockets[$AnImage])){
if(feof($sockets[$AnImage])){
如果(!isset($sizes[$AnImage]))$sizes[$AnImage]='';
$size[$AnImage]。=fgets($sockets[$AnImage],4096);
//echo(“HTML$AnImage DONE.”);
//回声(“[”$size[$AnImage]。“]”);
//冲洗();
fclose($sockets[$AnImage]);
未设置($sockets[$AnImage]);
$mysizes=ContentLoader::cleanResponse($sizes[$AnImage]);
//回声($size[$AnImage]);
//echo(ContentLoader::cleanResponse($size[$AnImage]);
如果(!is_数组($mysizes)){continue;}
如果($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。

听说过吗?@Orbling这是我指的扩展。但我不想安装额外的,而且我还没有安装rd非常好。在大多数系统上,分叉是多进程执行的基础。只是人们不经常在PHP中使用它,部分原因是PHP程序员不习惯这个概念和注意事项。有很多gotchas使用PHP来做这件事,但经过仔细处理,它是一种标准的、合理的分割进程的方法sing curl在大多数情况下都有很高的开销,但它的优点是通过您的Web服务器,因此可以在机器上实现负载平衡,等等。PHP并没有很好地针对并发性和并行处理进行定制。如果您正在生成内部请求,那么最好将工作交给Erlang。除非存在较大的b无法快速移植的库代码体。+1听起来是处理t的一个非常好的方法
            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']);