3

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

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

4

2 回答 2

1

有一种可行的方法。制作一个 cli php 文件,该文件在参数中获取它必须执行的操作并返回序列化生成的任何结果。

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

[编辑]我使用了您的工人示例,只需要在顶部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以及并行收集数据来进一步改进。

于 2013-07-16T16:43:07.853 回答
1

我会用socket_select(). 这样做,只有连接时间会累积,因为您可以从并行的套接字中读取。这会给你带来很大的性能提升。

于 2013-07-16T16:45:40.713 回答