【问题标题】:PHP proc_open opens multiple timesPHP proc_open 多次打开
【发布时间】:2011-01-23 20:38:17
【问题描述】:

我有一个用于通过 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 也是。

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

【问题讨论】:

  • 使用另一个过程工具来验证观察结果。您没有提到它是什么程序(可能会自行分叉到子进程中)。
  • @Christian:我们如何检查它?正如你所说,你没有提到它是什么程序。马里奥是完全正确的;你应该听他的。
  • 对不起,我的意思是“检查过”(我现在删除了评论以避免混淆)。我(的意思)是我用进程监视器检查了它。编辑:我确实听他的;)大声笑
  • 您能否为我们提供逐个案例的示例,以及每个案例的脚本执行多少次?确保还记下您执行脚本的时间。我担心即使输入相同,重复也会有所不同。
  • 你可以使用类似flock() php.net/manual/en/function.flock.php的东西来确保它只运行一次。

标签: php windows command-line-interface proc-open k2f


【解决方案1】:

您要测试它只运行一次的代码看起来有缺陷。

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

其次,您应该在函数结束时将$once 设置为false,否则将永远无法到达die

尝试添加一些日志来查看函数是否被调用了两次。

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

【讨论】:

  • 我在本地运行它,因此我可以看到每个会话以及打开的进程。程序在自己调用时只运行一次。我很肯定我原来的陈述是正确的。
  • @Christian - 当您向函数添加日志记录时,它是否似乎被多次调用,或者进程本身是否由 php windows 或应用程序启动多次?
  • @ByronWhitlock - 进程本身被多次加载。注释代码确保该函数只被调用一次。
  • @Christian Scinerras:你知道静态变量$once 对每个进程分别存在,每个进程可能有不同的值吗?即那行代码不会阻止不同的进程运行你的函数
  • @sje397 - 但我很肯定只有一个进程在运行该功能。该代码确保每个进程只调用一次函数。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

    我使用了这个命令:

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

    【讨论】:

      猜你喜欢
      • 2012-07-22
      • 1970-01-01
      • 2021-11-25
      • 1970-01-01
      • 1970-01-01
      • 2018-01-12
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多