PHP元搜索引擎的并行处理


PHP Parallel processing for a Metasearch Engine

我开发了一个元搜索引擎,我想做的优化之一是并行处理搜索API。想象一下,搜索引擎A在0.24秒内检索到结果,SE B在0.45秒内检索到,SE C在0.5秒内检索到。在其他开销的情况下,元搜索引擎可以在大约1.5秒内返回聚合结果,这是可行的。现在,我想做的是并行发送这些请求,而不是像目前那样串行发送,并将时间缩短到不到一秒钟。我调查过exec、forking、线程,由于各种原因,所有这些都失败了。现在我只花了一两天的时间在这上面,所以我可能错过了一些东西。理想情况下,我想在我的开发机器(localhost)上的WAMP堆栈上实现这一点,然后再看看如何在Linux Web服务器上实现。感谢您的帮助。

让我们举一个简单的例子:假设我们有两个文件要同时运行。文件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中使用它!

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

有一种可行的方法。制作一个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;
?>

还稍微修改了运行脚本-例如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以及并行收集数据来进一步改进。