Вопрос: PHP работает одновременно с несколькими скриптами


У меня есть массив с объектным сервером:

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"

Но весь процесс занял 10 секунд для 5 серверов по сравнению с 1 сервером менее 2 секунд. Почему это? В любом случае, чтобы уменьшить время? Я предполагаю, что команда exec ожидала, что выход будет назначен переменной перед переходом к следующему циклу? Я попытался немного поработать с Google, но большая часть ответа для него не была возвращена вообще. Мне нужен вывод, хотя


5


источник


Ответы:


Вы можете запускать свои скрипты одновременно с 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 секунды вместо 10,49 секунд с shell_exec(),

Обновление 1:  Большое спасибо Маркус А.О.  для указания потенциала оптимизации.

Обновление 2:  Изменен код, чтобы удалить возможность перезаписи. Результаты теперь находятся внутри $model,

Это также может показать, какой сервер отказался от соединения, если проблема с sshd влияет на вас.


7



Я не знаю, как сделать вашу логику быстрее, но я могу рассказать вам, как я использую отслеживать время работы, когда у меня есть сценарии. В начале скрипта поместите некоторый var $start = date('c'); и в конце просто echo ' start='.$start; echo ' end='.date(c); 


0



Да, вы правы: ваш PHP-скрипт ждет каждого ответа, прежде чем двигаться дальше.

Я предполагаю, что вы надеетесь запускать запросы на все серверы одновременно, вместо того, чтобы ждать ответа каждого сервера. В этом случае, если вы используете поточно-безопасную версию PHP, загляните в Pthreads , Один из вариантов - использовать cURL multi-exec  для создания асинхронных запросов. Тогда есть также pcntl_fork  что может помочь вам. Также см это  & это  поток для возможных потоков / асинхронных подходов.

Помимо этого, выполните проверку и проверку сценариев оболочки отдельно, чтобы узнать, где узкие места, и можете ли вы ускорить их. Это может быть проще, чем потоки / асинхронные настройки в PHP. Если у вас возникли проблемы с сетевой задержкой, напишите сценарий оболочки агрегатора, который выполняет другие скрипты и возвращает результаты в одном запросе, и вызывается только в вашем скрипте PHP.


0



Все, что вам нужно сделать, это добавить > /dev/null & в конце в Linux вы не получите результат, но он будет работать как фоновый (асинхронный) процесс.

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

см. также этот фоновый сценарий процесса из моего GitHub (он имеет совместимые с окнами процессы)

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

Ура!


0