我需要在 PHP 中进行并行处理,但是如果没有安装扩展,PHP 不支持它,所以我正在使用它multi_curl
来实现这一点。
main.php
- 构建一个 url 数组,它们都process.php
具有不同的 $_GET 参数。然后使用 multi_curl 执行它们。
process.php
- 每个线程的处理逻辑。
我只是想知道这是否是一种可行的做事方式。这是迟钝吗?它会导致很多开销吗?有没有更明智的方法来做到这一点?谢谢。
我需要在 PHP 中进行并行处理,但是如果没有安装扩展,PHP 不支持它,所以我正在使用它multi_curl
来实现这一点。
main.php
- 构建一个 url 数组,它们都process.php
具有不同的 $_GET 参数。然后使用 multi_curl 执行它们。
process.php
- 每个线程的处理逻辑。
我只是想知道这是否是一种可行的做事方式。这是迟钝吗?它会导致很多开销吗?有没有更明智的方法来做到这一点?谢谢。
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 )。
当然,一般来说,这是一种可行的做事方式,这就是功能存在的原因。
一如既往,魔鬼在细节中。多个并发请求会与其他进程竞争并消耗服务器资源;您将需要调节并发程度。
考虑到 PHP 不以任何合理的方式支持多处理,multi_curl 在您的情况下似乎是一个很好的解决方案!
如果您在 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
在此之后,您可以在“线程”继续工作的同时做自己的事情,然后,在一个循环中,您继续读取所有 $sockets[] 并测试 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。