PHP proc_open打开多次

发布于 2024-10-14 07:42:35 字数 1631 浏览 10 评论 0原文

我有一个实用程序函数,用于通过 CLI(cmd、bash 等)执行程序。它返回一个包含 3 个项目的数组:STDOUTSTDERREXIT CODE

到目前为止,它运行良好,没有出现任何问题。事实上,我遇到的问题并没有真正妨碍它的功能,但我担心性能。

问题是,在某些情况下,PHP 会多次运行相同的命令(在我的例子中为 3 次),即使它应该只执行一次。

/**
 * Executes a program and waits for it to finish, taking pipes into account.
 * @param string $cmd Command line to execute, including any arguments.
 * @param string $input Data for standard input.
 * @param boolean $log Whether to log execution failures or not (defaults to true).
 * @return array Array of "stdout", "stderr" and "return".
 */
public static function execute($cmd,$stdin=null,$log=true){
    //static $once=true; if(!$once)die; $once=false;
    $proc=proc_open($cmd, array(
        0=>array('pipe','r'),
        1=>array('pipe','w'),
        2=>array('pipe','w')   ), $pipes);
    fwrite($pipes[0],$stdin);                fclose($pipes[0]);
    $stdout=stream_get_contents($pipes[1]);  fclose($pipes[1]);
    $stderr=stream_get_contents($pipes[2]);  fclose($pipes[2]);
    $return=proc_close($proc);
    if($return!=0 && $log)
        xlog('Error: Program execution returned failure.',$stdout,$stderr,$return);
    return array( 'stdout'=>$stdout, 'stderr'=>$stderr, 'return'=>$return );
}

请注意注释行(第 9 行)。那是为了测试。我启用它是为了确保目标程序只运行一次(我认为我的代码可能以某种方式调用相同的函数)。 但即使启用了该行,该程序仍然运行多次。

事实上,我的代码中有两个地方正在执行相同的程序(在不同的场合)。它们的命令行是相同的。

然而,有一种情况,程序运行一次,而在这种情况下,PHP 运行程序 3 次。

我一直在 Process Explorer 下监视并看到这种行为。我使用的是 Windows 7 x64。该程序是 32 位的,PHP 也是如此。

编辑:有问题的程序是定制开发的,它不会打开新的进程。

I have a utility function used for executing a program through CLI (cmd, bash etc). It returns an array of 3 items: STDOUT, STDERR and EXIT CODE.

So far, it's been working nicely without issues. In fact, the problem I have with it doesn't really hinder it's functionality, but I'm concerned about performance.

The problem is that in certain cases, PHP runs the same command multiple times (3 times in my case), even if it was supposed to only do this once.

/**
 * Executes a program and waits for it to finish, taking pipes into account.
 * @param string $cmd Command line to execute, including any arguments.
 * @param string $input Data for standard input.
 * @param boolean $log Whether to log execution failures or not (defaults to true).
 * @return array Array of "stdout", "stderr" and "return".
 */
public static function execute($cmd,$stdin=null,$log=true){
    //static $once=true; if(!$once)die; $once=false;
    $proc=proc_open($cmd, array(
        0=>array('pipe','r'),
        1=>array('pipe','w'),
        2=>array('pipe','w')   ), $pipes);
    fwrite($pipes[0],$stdin);                fclose($pipes[0]);
    $stdout=stream_get_contents($pipes[1]);  fclose($pipes[1]);
    $stderr=stream_get_contents($pipes[2]);  fclose($pipes[2]);
    $return=proc_close($proc);
    if($return!=0 && $log)
        xlog('Error: Program execution returned failure.',$stdout,$stderr,$return);
    return array( 'stdout'=>$stdout, 'stderr'=>$stderr, 'return'=>$return );
}

Note the commented line (line 9). That was for testing. I enabled it to ensure the target program only runs once (I was thinking my code may be calling the same function somehow).
But even with that line enabled, the program still ran multiple times.

As it is, I have 2 places in my code where I'm executing the same program (on different occasions). The command line is the same for both of them.

However, on one occasion, the program runs once, while in the occasion, PHP runs the program 3 times.

I've been monitoring and seeing this behavior under Process Explorer. I'm using Windows 7 x64. The program is 32 bit, as is PHP.

Edit: The program in question is custom developed, and it doesn't open new processes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

—━☆沉默づ 2024-10-21 07:42:35

用于测试其仅运行一次的代码看起来有缺陷。

如果您有 2 个 php 进程正在运行,它们将不会共享静态变量。因此,您可能有并发请求,导致其运行多次。

其次,您应该在函数末尾将 $once 设置为 false,否则永远不会到达 die

尝试添加一些日志记录以查看该函数是否被调用两次。

创建一些仅运行外部应用程序的单元/压力测试。如果您看到多个进程,那么您的应用程序有问题,而不是 php 代码。

Your code to test that it is run only once looks flawed.

If you have 2 php processes running they will not share a static variable. So it could be possible you have having simultaneous requests causing this to run more than once.

Second, you should be setting $once to false at the end of the function, otherwise the die will never be reached.

Try adding some logging to see if the function is being called from twice.

Create some unit/stress tests that just run the external application. If you see multiple processes, then there is something with your app that is wrong, not the php code.

陈年往事 2024-10-21 07:42:35

这很奇怪。如果没有完整的代码,很难弄清楚。

如果您的服务器多次调用同一页面,我最好的选择是它可能与 CPU 循环过程有关。 PHP 没有时间将静态变量设置为 false,因为同时还有对此方法的另一个请求。另一种可能性是 PHP 无法正确隔离静态值,并且对此方法的不同请求可以读取不同的内存位置,直到 PHP 同步这些值。

It is very strange. And It is very hard to figure out without the full code.

If you are stressing your server calling the same page several times, my best bet it is probably related to the CPU round robin process. The PHP does not have time to set the static variable to false because at the same there are an another request to this method. Other possibility is the PHP is failing to isolate properly the static value and the different request to this method can read different memory position until the PHP sinchronize the values.

记忆之渊 2024-10-21 07:42:35

我知道这可能不是最好的选择,但这就是我所做的。虽然这是在 Linux 上进行的,但我确信有办法将其移植到 Windows 上。

我所做的是运行 pgrep 并检查是否已经存在这样的命令以及它是否只是退出。
正如您所说,您正在运行相同的命令(具有确切的参数),因此只需检查是否已经有命令正在运行并分别执行即可。

我使用了这个命令:

$pid = shell_exec('pgrep -cfx "/* My command */"');
if ($pid > 1) return -1;

I know this may not be the best option, but this is what I did. Though this was on Linux, but I'm sure there is way to port this to Windows.

What I did, was run pgrep and check if there already existed a command like this and if it did simply exit.
As you said you are running same command (with exact parameters), so just check if there already is a command running and act respectively.

I used this command:

$pid = shell_exec('pgrep -cfx "/* My command */"');
if ($pid > 1) return -1;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文