PHP同时运行多个脚本

时间:2016-12-23 09:25:50

标签: php shell foreach exec shell-exec

我有一个像这样的对象服务器的数组:

Array
(
    [0](
                (
                    [id] => 1
                    [version] => 1
                    [server_addr] => 192.168.5.210
                    [server_name] => server1
                )
        )
    [1](
                (
                    [id] => 2
                    [server_addr] => 192.168.5.211
                    [server_name] => server2
                )
        )
)

通过运行下面的代码,我可以获得所需的输出

foreach ($model as $server) {
        $cpu_usage = shell_exec('sudo path/to/total_cpu_usage.sh '.$server->server_addr);
        $memory_usage = shell_exec('sudo path/to/total_memory_usage.sh '.$server->server_addr);
        $disk_space = shell_exec('sudo path/to/disk_space.sh '.$server->server_addr);
        $inode_space = shell_exec('sudo path/to/inode_space.sh '.$server->server_addr);
        $network = shell_exec('sudo path/to/network.sh '.$server->server_addr);
        exec('sudo path/to/process.sh '.$server->server_addr, $processString);
        $processArray = array();
        foreach ($processString as $i) {
          $row = explode(" ", preg_replace('/\s+/', ' ', $i));
          array_push($processArray,$row);
        }
        $datetime = shell_exec('sudo path/to/datetime.sh '.$server->server_addr);
        echo $cpu_usage;
        echo $mem_usage;
        echo $disk_space;
        ......
}

我的脚本类似于:

#!/bin/bash
if [ "$1" == "" ]
then
        echo "To start monitor, please provide the server ip:"
        read IP
else
        IP=$1
fi

ssh root@$IP "date"

但是,对于5台服务器,整个过程需要10秒,而不到2秒则需要1台服务器。这是为什么?反正有减少时间吗?我的猜测是,在进入下一个循环之前,exec命令正在等待输出分配给变量?我尝试谷歌一点点,但大多数答案是没有返回任何输出...我需要输出

4 个答案:

答案 0 :(得分:9)

您可以使用popen()同时运行脚本,稍后使用fread()获取输出。

//execute
foreach ($model as $server) {
    $server->handles = [
        popen('sudo path/to/total_cpu_usage.sh '.$server->server_addr, 'r'),
        popen('sudo path/to/total_memory_usage.sh '.$server->server_addr, 'r'),
        popen('sudo path/to/disk_space.sh '.$server->server_addr, 'r'),
        popen('sudo path/to/inode_space.sh '.$server->server_addr, 'r'),
        popen('sudo path/to/network.sh '.$server->server_addr, 'r'),
    ];
}

//grab and store the output, then close the handles
foreach ($model as $server) {
    $server->cpu_usage = fread($server->handles[0], 4096);
    $server->mem_usage = fread($server->handles[1], 4096);
    $server->disk_space = fread($server->handles[2], 4096);
    $server->inode_space = fread($server->handles[3], 4096);
    $server->network = fread($server->handles[4], 4096);

    foreach($server->handles as $h) pclose($h);
}

//print everything
print_r($model);

我测试了一个类似的代码,执行5个脚本,睡眠时间为2秒,整个过程只花了2.12秒 用shell_exec()代替10.49秒。

更新1:非常感谢Markus AO指出优化潜力。

更新2:修改代码以消除覆盖的可能性。 结果现在位于$model内。

如果关于sshd的问题影响了你,这也可以显示哪个服务器拒绝了连接。

答案 1 :(得分:0)

我不知道如何让你的逻辑更快,但我可以告诉你如何在我有脚本时跟踪运行时间。在脚本的开头放置一些var $start = date('c');,最后只是简单的echo ' start='.$start; echo ' end='.date(c);

答案 2 :(得分:0)

是的,你是对的:你的PHP脚本在继续前进之前等待每个响应。

我认为您希望同时向所有服务器运行请求,而不是等待每个服务器响应。在这种情况下,假设您运行的是线程安全的PHP版本,请查看pthreads。一种选择是使用cURL multi-exec来发出异步请求。然后还有pcntl_fork可能会帮助你。另见this& this线程用于可能的线程/异步方法。

除此之外,还要单独测试和测试shell脚本以查看瓶颈的位置,以及是否可以加快它们的速度。这可能比PHP中的线程/异步设置更容易。如果您遇到网络延迟问题,那么编写一个聚合器shell脚本来执行其他脚本,并在一个请求中返回结果,并且只在PHP脚本中调用它。

答案 3 :(得分:0)

你需要做的就是在Linux上添加一个> /dev/null &,你不会得到输出,但它将作为后台(异步)进程运行。

shell_exec('sudo path/to/datetime.sh '.$server->server_addr.'  > /dev/null &');

另请参阅我的GitHub中的后台进程脚本(它具有与Windows兼容的后台进程)

https://github.com/ArtisticPhoenix/MISC/blob/master/BgProcess.php

干杯!