我开发了一个元搜索引擎,我想做的一个优化就是并行处理搜索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中使用它!
答案 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()
。这样做,只有连接时间是累积的,因为您可以并行读取套接字。这将为您提供大性能提升。