我环顾四周寻找这个,我似乎找不到任何正在努力去做我的人。
我有通过_POST请求传递给我的函数的信息。基于该数据,我运行一个exec命令来运行一定次数的TCL脚本(使用不同的参数,基于post变量)。现在,我在foreach中有exec所以这需要永远运行(TCL脚本需要15秒左右才能返回,所以如果我需要运行100次,我有点问题)。这是我的代码:
public function executeAction(){
//code to parse the _POST variable into an array called devices
foreach($devices as $devID){
exec("../path/to/script.tcl -parameter1 ".$device['param1']." -parameter2 ".$device['param2'], $execout[$devID]);
}
print_r($execout);
}
显然,这段代码只是删除了大块的摘录,但希望它足以证明我正在尝试做的事情。
我需要立即运行所有的执行程序,我需要等待它们全部完成才能返回。我还需要存储在名为$ execout的数组中的所有脚本的输出。
有什么想法吗?
感谢!!!
答案 0 :(得分:6)
如果您将exec()
电话放在单独的脚本中,则可以使用curl_multi_exec()
并行多次调用该外部脚本。这样,您可以在单独的请求中进行所有调用,这样它们就可以同时执行。轮询&$still_running
以查看所有请求何时完成,之后您可以收集每个请求的结果。
更新:这里的a blog post详细说明了我所描述的内容。
根据上面链接的博客文章,我将以下示例放在一起。
脚本并行运行:
// waitAndDate.php
<?php
sleep((int)$_GET['time']);
printf('%d secs; %s', $_GET['time'], shell_exec('date'));
脚本并行调用:
// multiExec.php
<?php
$start = microtime(true);
$mh = curl_multi_init();
$handles = array();
// create several requests
for ($i = 0; $i < 5; $i++) {
$ch = curl_init();
$rand = rand(5,25); // just making up data to pass to script
curl_setopt($ch, CURLOPT_URL, "http://domain/waitAndDate.php?time=$rand");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_multi_add_handle($mh, $ch);
$handles[] = $ch;
}
// execute requests and poll periodically until all have completed
$isRunning = null;
do {
curl_multi_exec($mh, $isRunning);
usleep(250000);
} while ($isRunning > 0);
// fetch output of each request
$outputs = array();
for ($i = 0; $i < count($handles); $i++) {
$outputs[$i] = trim(curl_multi_getcontent($handles[$i]));
curl_multi_remove_handle($mh, $handles[$i]);
}
curl_multi_close($mh);
print_r($outputs);
printf("Elapsed time: %.2f seconds\n", microtime(true) - $start);
以下是我运行几次时收到的一些输出:
Array
(
[0] => 8 secs; Mon Apr 2 19:01:33 UTC 2012
[1] => 8 secs; Mon Apr 2 19:01:33 UTC 2012
[2] => 18 secs; Mon Apr 2 19:01:43 UTC 2012
[3] => 11 secs; Mon Apr 2 19:01:36 UTC 2012
[4] => 8 secs; Mon Apr 2 19:01:33 UTC 2012
)
Elapsed time: 18.36 seconds
Array
(
[0] => 22 secs; Mon Apr 2 19:02:33 UTC 2012
[1] => 9 secs; Mon Apr 2 19:02:20 UTC 2012
[2] => 8 secs; Mon Apr 2 19:02:19 UTC 2012
[3] => 11 secs; Mon Apr 2 19:02:22 UTC 2012
[4] => 7 secs; Mon Apr 2 19:02:18 UTC 2012
)
Elapsed time: 22.37 seconds
Array
(
[0] => 5 secs; Mon Apr 2 19:02:40 UTC 2012
[1] => 18 secs; Mon Apr 2 19:02:53 UTC 2012
[2] => 7 secs; Mon Apr 2 19:02:42 UTC 2012
[3] => 9 secs; Mon Apr 2 19:02:44 UTC 2012
[4] => 9 secs; Mon Apr 2 19:02:44 UTC 2012
)
Elapsed time: 18.35 seconds
希望有所帮助!
一方面注意:确保您的Web服务器可以处理这么多并行请求。如果它按顺序服务它们或者只能同时服务很少,那么这种方法很少或根本没有。 : - )
答案 1 :(得分:5)
PHP的exec函数将始终等待执行的响应。但是你可以发送stdout&amp;进程的stderror到/ dev / null(在unix上)并且几乎立即执行这些所有脚本。这可以通过添加..
来完成 '> /dev/null 2>&1 &'
到执行字符串的末尾。
但是!这意味着他们将分开并独立完成处理。可能值得让他们在某处写回复。你可以创建一个监听器来选择并处理它。
答案 2 :(得分:1)
引用PHP文档:
注意:
如果使用此功能启动程序,为了使其在后台继续运行,必须将程序的输出重定向到文件或其他输出流。如果不这样做将导致PHP挂起,直到程序执行结束。
因此,如果您将输出重定向到文件中,则可以在后台执行:
exec("../path/to/script.tcl -parameter1 ".$device['param1']." -parameter2 ".$device['param2']." > outputfile.txt", $execout[$devID]);
但是如果你想等待所有的高管在继续之前完成,你必须从外部脚本进行回调。也许是这样的:
exec("../path/to/script.tcl -parameter1 ".$device['param1']." -parameter2 ".$device['param2']." > ../path/to/outputfile.txt; ".PHP_BINDIR.DIRECTORY_SEPARATOR."php ../path/to/callback.php", $execout[$devID]);
像这样,你的callback.php脚本将在每个exec.exec执行后调用。
也许你可以用这些技巧做点什么。
答案 3 :(得分:1)
您需要稍微修改一下脚本
答案 4 :(得分:0)
查看libputil库中的ExecFuture andFutureIterator:
https://secure.phabricator.com/book/libphutil/class/ExecFuture/
使用非常好的语法完全符合您的要求:
$futures = array();
foreach ($files as $file) {
$futures[$file] = new ExecFuture("gzip %s", $file);
}
foreach (new FutureIterator($futures) as $file => $future) {
list($err, $stdout, $stderr) = $future->resolve();
if (!$err) {
echo "Compressed {$file}...\n";
} else {
echo "Failed to compress {$file}!\n";
}
}