PHP元搜索引擎的并行处理

时间:2013-07-16 16:32:44

标签: php parallel-processing meta-search

我开发了一个元搜索引擎,我想做的一个优化就是并行处理搜索API。想象一下,结果是在0.24秒内从搜索引擎A中检索到的,在0.45秒内从SE B中检索到,在0.5秒内从SE C中检索到。使用其他开销,元搜索引擎可以在大约1.5秒内返回聚合结果,这是可行的。现在我想做的是像目前那样并行发送这些请求而不是串行发送,并将时间缩短到不到一秒。我已经调查过exec,forking,threading等等,由于种种原因,都失败了。现在我只花了一两天的时间,所以我可能错过了一些东西。理想情况下,我想在我的开发机器(localhost)上的WAMP堆栈上实现它,然后看看如何在Linux webserver上实现。任何帮助表示赞赏。

我们举一个简单的例子:假设我们有两个同时要运行的文件。文件1:

<?php
// file1.php
echo 'File 1 - Test 1'.PHP_EOL;
$sleep = mt_rand(1, 5);
echo 'Start Time: '.date("g:i:sa").PHP_EOL;
echo 'Sleep Time: '.$sleep.' seconds.'.PHP_EOL;
sleep($sleep);
echo 'Finish Time: '.date("g:i:sa").PHP_EOL;
?>

现在,想象文件二是相同的...这个想法是,如果并行运行,命令行输出的时间应该是相同的,例如:

File 1 - Test 1
Start Time: 9:30:43am
Sleep Time: 4 seconds.
Finish Time: 9:30:47am

但无论我使用exec,popen还是其他什么,我都无法在PHP中使用它!

2 个答案:

答案 0 :(得分:1)

有一种可行的方法。制作一个cli php文件,该文件可以获取参数,并返回生成序列化的结果。

在您的主应用程序中,您可以popen尽可能多地使用这些工作人员,然后在一个简单的循环中收集输出:

[edit] 我使用了您的工作人员示例,只需chmod +x并在顶部添加#!/usr/bin/php行:

#!/usr/bin/php
<?php
echo 'File 1 - Test 1'.PHP_EOL;
$sleep = mt_rand(1, 5);
echo 'Start Time: '.date("g:i:sa").PHP_EOL;
echo 'Sleep Time: '.$sleep.' seconds.'.PHP_EOL;
sleep($sleep);
echo 'Finish Time: '.date("g:i:sa").PHP_EOL;
?>

还修改了运行脚本 - ex.php:

#!/usr/bin/php
<?php
$pha=array();
$res=array();
$pha[1]=popen("./file1.php","r");
$res[1]='';
$pha[2]=popen("./file2.php","r");
$res[2]='';
while (list($id,$ph)=each($pha)) {
    while (!feof($ph))
        $res[$id].=fread($ph,8192);
    pclose($ph);
}
echo $res[1].$res[2];

这是结果,在cli中测试时(从web调用ex.php时相同,但应修复file1.php和file2.php的路径):

$ time ./ex.php 
File 1 - Test 1
Start Time: 11:00:33am
Sleep Time: 3 seconds.
Finish Time: 11:00:36am
File 2 - Test 1
Start Time: 11:00:33am
Sleep Time: 4 seconds.
Finish Time: 11:00:37am

real  0m4.062s
user  0m0.040s
sys   0m0.036s

如结果所示,一个脚本需要3秒钟才能执行,另一个需要4个脚本。两个脚本并行运行4秒。

[结束编辑]

通过这种方式,慢速操作将并行运行,您只能以串行方式收集结果。

最后,需要(最慢的工作时间)+(收集时间)执行。由于收集结果的时间和反序列化的时间等可能会被忽略,因此您可以获得最慢请求时间的所有数据。

作为旁注,您可以尝试使用比内置快速更快的igbinary序列化程序。

如评论中所述:

worker.php在Web请求之外执行,您必须通过参数传递其所有状态。传递参数也可能是处理所有转义,安全性等问题,因此无效但简单的方法是使用base64。

这种方法的一个主要缺点是调试起来不容易。

使用stream_select代替fread并同时收集数据可以进一步改进。

答案 1 :(得分:1)

我会使用socket_select()。这样做,只有连接时间是累积的,因为您可以并行读取套接字。这将为您提供性能提升。