Компонент Symfony2 Process - невозможно создать канал и запустить новый процесс

Я использую компонент Symfony2 Process для ручного управления пулом процессов.

В приведенном ниже примере я перезапускаю 2 простых процесса каждые 2 секунды и отслеживаю, что происходит. Приложение ломается после перезапуска этих процессов несколько сотен раз.

Выполнение остановлено, и я получаю следующее предупреждение PHP:

proc_open(): unable to create pipe Too many open files

а затем компонент Symfony Process генерирует следующее исключение:

[Symfony\Component\Process\Exception\RuntimeException]  
Unable to launch a new process.   

Я вручную отслеживал общее количество открытых процессов, и оно никогда не превышает ожидаемого предела.

Приведенный ниже упрощенный фрагмент кода является частью команды Symfony2 и запускается из CLI (например, app/console hamster:run):

    $processes[] = new Process("ls > /dev/null", null, null, null, 2);
    $processes[] = new Process("date > /dev/null", null, null, null, 2);

    while (count($processes) > 0) {
        foreach ($processes as $i => $process) {
            if (!$process->isStarted()) {
                $process->start();

                continue;
            }

            try {
                $process->checkTimeout();
            } catch (\Exception $e) {
                // Don't stop main thread execution
            }

            if (!$process->isRunning()) {
                // All processes are timed out after 2 seconds and restarted afterwards
                $process->restart();
            }
        }

        usleep($sleep * 1000000);
    }

Это приложение выполняется на сервере MAC под управлением OS X 10.8.4.

Я был бы признателен за любые подсказки о том, как преследовать корень этой проблемы.

Обновление №1: я упростил свою функцию для работы с базовыми командами, такими как ls и date, для более быстрого тестирования. Все еще похоже, что команда Process не работает после запуска и остановки около 1000-1500 процессов.

Я подозревал, что proc_close() вызывался неправильно для каждого процесса, но дальнейшее расследование показало, что здесь это не так.


person ukliviu    schedule 11.09.2013    source источник


Ответы (1)


Дескрипторы файлов не собираются мусором, поэтому они в конечном итоге заполняются (лимит ОС или лимит php, не уверен), но вы можете исправить это, добавив явный вызов сборки мусора:

gc_collect_cycles();
usleep($sleep * 1000000);

Кроме того, имейте в виду, что сборка мусора не очень хорошо работает внутри цикла foreach из-за того, как php отображает временные переменные массива $foo as $bar => $var в память. Если вам это нужно в этой части кода, вы можете переключить его на что-то вроде этого, что, как я думаю, должно разрешить сборку мусора внутри цикла for:

$processes[] = new Process("ls > /dev/null", null, null, null, 2);
$processes[] = new Process("date > /dev/null", null, null, null, 2);

$sleep = 0;

do {
    $count = count($processes);
    for($i = 0; $i < $count; $i++) {
        if (!$processes[$i]->isStarted()) {
            $processes[$i]->start();

            continue;
        }

        try {
            $processes[$i]->checkTimeout();
        } catch (\Exception $e) {
            // Don't stop main thread execution
        }

        if (!$processes[$i]->isRunning()) {
            // All processes are timed out after 2 seconds and restarted afterwards
            $processes[$i]->restart();
        }

        gc_collect_cycles();
    }

    usleep($sleep * 1000000);
} while ($count > 0);
person cbednarski    schedule 12.09.2013
comment
Хорошая точка зрения. Я не рассматривал необходимость ручного вызова сборщика мусора. Выполнение некоторых дополнительных тестов (перезапуск процессов более 100 000 раз) с gc_collect_cycles() подтвердило ваше решение. Спасибо! - person ukliviu; 12.09.2013
comment
лучшим способом было бы ->stop(0) экземпляр процесса, когда это будет сделано, это эффективно закроет дескрипторы открытых файлов, не полагаясь на __destruct, вызываемый сборщиком мусора. - person Florian Klein; 28.09.2017
comment
Вы спасли мне жизнь этим! Нужен ли сон? - person StockBreak; 03.03.2020