首页 > 解决方案 > (PHP) 等待子进程超时退出

问题描述

我使用 proc_open() 启动了一个子进程,现在我需要等到子进程完成 - 或 - 直到 X 秒过去,以先到者为准。解决该问题的一种明显方法是使用 while() 循环检查每次迭代,如下所示:

$starttime = microtime(true);
$unused = [];
$ph = proc_open($cmd, $unused, $unused);
$terminated = false; // < protection against running pkilltree() twice
// OPTIMIZE ME: use stream_select() or something instead of sleep-loop
while (($status = proc_get_status($ph))['running']) {
    usleep(100 * 1000); // *1000 = ms
    if (! $terminated && microtime(true) - $starttime > MAX_RUNTIME_SECONDS) {
        $terminated = true;
        echo 'max runtime reached (' . MAX_RUNTIME_SECONDS . ' seconds), terminating...';
        pkilltree((int) ($status['pid']));
        // proc_terminate ( $ph, SIGKILL );
    }
}

但是,如果该过程在 1 毫秒内完成,那么等待 99 毫秒等待 sleep() 会(相对)浪费很多时间,我可以每 1 毫秒而不是每 100 毫秒检查一次,但这会浪费很多 CPU。使用 linux api 可能会使用sigtimedwait() 来等待 SIGCHLD,但在 PHP 中,我怀疑(但尚未正确验证)PHP 解释器本身从用户态 php 代码中拦截并隐藏 SIGCHLD ,所以..有什么建议吗?

标签: phpexecwait

解决方案


我只是好奇,是否有必要使用 proc_open()?因为作为您的示例代码,可以使用 exec() 函数来完成它,但它需要一个简单的 CLI 工具来使用,它的timeout.

timeout - 运行有时间限制的命令 Start COMMAND,如果在 DURATION 之后仍然运行,则终止它

因此,除非您想对孩子做其他事情,否则此代码可以替代您的代码。

$starttime = microtime(true);
exec("timeout " . MAX_RUNTIME_SECONDS . " $cmd");
$terminated = false;
if (! $terminated && microtime(true) - $starttime > MAX_RUNTIME_SECONDS) {
    $terminated = true;
    echo 'max runtime reached (' . MAX_RUNTIME_SECONDS . ' seconds), terminating...';
}

这个技巧我多年来一直在 PHP 中使用多处理。它对我来说非常完美。


推荐阅读