Symfony2 进程组件 - 无法创建管道并启动新进程 [英] Symfony2 Process component - unable to create pipe and launch a new process

查看:69
本文介绍了Symfony2 进程组件 - 无法创建管道并启动新进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Symfony2 Process 组件来手动管理进程池.

I'm using the Symfony2 Process component to manually manage a pool of processes.

在下面的示例中,我每 2 秒重新启动 2 个简单进程并监视发生的情况.重新启动这些进程数百次后,应用程序就会中断.

In the example below I restart 2 simple processes every 2 seconds and monitor what happens. The application breaks after restarting these processes a few hundred times.

执行已停止,我收到以下 PHP 警告:

Execution is stopped and I get the following PHP warning:

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

然后Symfony Process组件抛出以下异常:

and then the following exception is thrown by the Symfony Process component:

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

我手动监控了打开进程的总数,它从未超过预期的限制.

I've manually monitored the total number of open processes and it never goes up the expected limit.

下面的简化片段是 Symfony2 命令的一部分,正在从 CLI 运行(例如 app/console hamster:run):

The below simplified snippet is part of a Symfony2 command and is being runned from the CLI (e.g. 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);
    }

此应用程序正在运行 OS X 10.8.4 的 MAC 服务器上运行.

This application is being run on a MAC server running OS X 10.8.4.

如果您能提供有关如何解决此问题根源的任何提示,我将不胜感激.

I would appreciate any hints on how to pursue the root of this issue.

更新 #1: 我已经简化了我的函数以使用诸如 lsdate 之类的基本命令来加快测试速度.在启动和停止大约 1000-1500 个进程后,Process 命令似乎仍然失败.

Update #1: I've simplified my function to work with basic commands like ls and date for faster testing. It still looks like the Process command fails after starting and stopping about 1000-1500 processes.

我怀疑没有为每个进程正确调用 proc_close(),但进一步调查显示情况并非如此.

I suspected that proc_close() was not being called correctly for each process, but further investigation revealed that's not the case here.

推荐答案

文件句柄没有被垃圾收集,所以它们最终会填满(os limit 或 php limit,不确定),但你可以通过添加一个显式垃圾收集调用:

The file handles are not being garbage collected, so they eventually fill up (os limit or php limit, not sure), but you can fix it by adding an explicit garbage collection call:

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

另外,请注意垃圾收集在 foreach 循环中不能很好地工作,因为 php 将临时 $foo 映射为 $bar =>$var 数组变量放入内存.如果您在代码的那部分需要它,您可以将其切换为类似这样的内容,我认为应该允许在 for 循环内进行垃圾收集:

Also, be forwarned that garbage collection doesn't work very well inside a foreach loop because of the way that php maps the temporary $foo as $bar => $var array variables into memory. If you need it in that part of the code you could switch it to something like this instead, which I think should allow for garbage collection inside the for loop:

$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);

这篇关于Symfony2 进程组件 - 无法创建管道并启动新进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆