【问题标题】:PHP using proc_open so that it doesn't wait for the script it opens (runs) to finish?PHP 使用 proc_open 以便它不等待它打开(运行)的脚本完成?
【发布时间】:2010-08-06 04:11:52
【问题描述】:

我在这方面花了一段时间,但无法让它发挥作用,我很抱歉,因为我早些时候问了一个与此相关的问题,但将其删除,以便我可以做更多的研究来缩小问题的范围,此时我被困住了,因为我认为我有这个解决方案,但它没有按我预期的那样工作。我找到了一个论坛,有人问了一个类似的问题,他们给出了如下代码,我正在尝试..它确实运行脚本,但它仍然等待它完成,然后再转到 PHP 代码中的下一行

    proc_close(proc_open ("/var/www/other_scripts/perl/apps/emails_extract_from_url.pl \"$stoopid\"", array(), $foo));

【问题讨论】:

    标签: php command-line proc-open


    【解决方案1】:

    嘿,我最近一直在使用 proc_open,它从不等它完成后再继续。确保你指定了管道,而不是仅仅使用一个空的 array()

    $descriptorspec = array(
       0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
       1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
       2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
    );
    

    并将 proc_open 分配给一个变量。

    $myProc = proc_open("/var/www/other_scripts/perl/apps/emails_extract_from_url.pl \"$stoopid\"", $descriptorspec , $foo)
    

    然后您可以使用proc_get_status($myProc); 获取进程的状态

    更多信息在这里http://au.php.net/proc_open

    关于关闭的更多信息。

    $temp = fgets($this->open_pipes[$thread_id][1], 1024);
    if($this->checkFinishedThread($thread_id))
    {
        fclose($this->open_pipes[$thread_id][1]);
        proc_close($thread);
    }
    
    function checkFinishedThread($thread_id)
    {
        $test = stream_get_meta_data($this->open_pipes[$thread_id][1]);
        if($test['eof'] == 1)
            return true;
        return false;
    }
    

    【讨论】:

    • 谢谢,我会检查的。我只是去一个帖子,那个人说要这样做,它应该可以工作,所以我会按照你的建议修改它
    • 更新:我已经尝试过您发布的内容,但它仍在等待它调用的脚本完成,我发现这很奇怪.. 我正在使用 PHP 和 apache(所以我打电话它来自网络浏览器),所以我不知道这是否会以某种方式影响它
    • 嗯,它可能。我通常在命令行上运行时使用它。但是在说我确定我已经在浏览器中完成了它并且它已经工作了。你能把整个脚本贴在你的帖子里吗?
    • ozatomic 你能说出你在哪个版本的 php 和 os 上测试它并且它有效吗?对我来说,它在命令行、apache 和 lighttpd 的 ubuntu 和 centos 下挂在 proc_close 上很长时间。
    • 是的,我也遇到过这种情况。我解决这个问题的方法是在关闭它之前进行检查。我已更新我的答案以包含这些信息。
    【解决方案2】:

    我在玩 proc_open 时的一些代码
    我遇到了 proc_close 问题(10 到 30 秒),所以我只是使用 linux 命令 kill 杀死了该进程

    
    
    $options=array();
    $option['sleep-after-destroy']=0;
    $option['sleep-after-create']=0;
    $option['age-max']=40;
    $option['dir-run']=dirname(__FILE__);
    $option['step-sleep']=1;
    $option['workers-max']=(int)file_get_contents($maxworkers_file);
    $option['destroy-forcefull']=1;
    
    $workers=array();
    
    function endAWorker($i,$cansleep=true) {
            global $workers;
            global $option;
            global $child_time_limit;
            if(isset($workers[$i])) {
                    @doE('Ending worker [['.$i.']]'."\n");
                    if($option['destroy-forcefull']==1) {
                            $x=exec('ps x | grep "php check_working_child.php '.$i.' '.$child_time_limit.'" | grep -v "grep" | grep -v "sh -c"');
                            echo 'pscomm> '.$x."\n";
                            $x=explode(' ',trim(str_replace("\t",' ',$x)));
                            //print_r($x);
                            if(is_numeric($x[0])) {
                                    $c='kill -9 '.$x[0];
                                    echo 'killcommand> '.$c."\n";
                                    $x=exec($c);
                            }
                    }
                    @proc_close($workers[$i]['link']);
                    unset($workers[$i]);
            }
            if($cansleep==true) {
                    sleep($option['sleep-after-destroy']);
            }
    }
    
    function startAWorker($i) {
            global $workers;
            global $option;
            global $child_time_limit;
    
            $runcommand='php check_working_child.php '.$i.' '.$child_time_limit.' > check_working_child_logs/'.$i.'.normal.log';
            doE('Starting [['.$i.']]: '.$runcommand."\n");
            $workers[$i]=array(
                    'desc' => array(
                            0 => array("pipe", "r"),
                            1 => array("pipe", "w"),
                            2 => array("file", 'check_working_child_logs/'.$i.'.error.log', "a")
                            ),
                    'pipes'                 => null,
                    'link'                  => null,
                    'start-time'    => mktime()
                    );
            $workers[$i]['link']=proc_open(
                    $runcommand,
                    $workers[$i]['desc'],
                    $workers[$i]['pipes'],
                    $option['dir-run']
                    );
            sleep($option['sleep-after-create']);
    }
    
    function checkAWorker($i) {
            global $workers;
            global $option;
            $temp=proc_get_status($workers[$i]['link']);
            if($temp['running']===false) {
                    doE('Worker [['.$i.']] finished'."\n");
                    if(is_file('check_working_child_logs/'.$i.'.normal.log') && filesize('check_working_child_logs/'.$i.'.normal.log')>0) {
                            doE('--------'."\n");
                            echo file_get_contents('check_working_child_logs/'.$i.'.normal.log');
                            doE('-------'."\n");
                    }
                    endAWorker($i);
            } else {
                    if($option['age-max']>0) {
                            if($workers[$i]['start-time']+$option['age-max']$v) {
                    endAWorker($i,false);
            }
            @doE('Done killing workers.'."\n");
    }
    
    register_shutdown_function('endAllWorkers');
    
    while(1) {
            $step++;
            foreach($workers as $index=>$v) {
                    checkAWorker($index);
            }
            if(count($workers)==$option['workers-max']) {
            } elseif(count($workers)$option['workers-max']) {
                    $wl=array_keys($workers);
                    $wl=array_pop($wl);
                    doE('Killing worker [['.$wl.']]');
                    endAWorker($wl[0]);
            }
    }
    
    

    【讨论】:

    • 是的,我遇到了同样的问题,因为我的 PHP 脚本实际上并没有等待,我只是认为这是因为应该完成的 perl 脚本仍在运行......它似乎做一个命令行 kill 是一个好方法
    • doe() 实际上做了一个回显,忘记了函数。
    【解决方案3】:

    您需要在命令行参数的末尾添加一个符号 (&):

    proc_close(proc_open ("/var/www/other_scripts/perl/apps/emails_extract_from_url.pl \"$stoopid\" & ", array(), $foo)); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-24
      • 2013-05-17
      • 2011-05-22
      • 2016-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多