복붙노트

PHP는 백그라운드 프로세스를 실행

PHP

PHP는 백그라운드 프로세스를 실행

사용자 작업에 따라 디렉토리 복사본을 실행해야하지만 디렉토리가 상당히 큽니다. 따라서 사용자가 복사본을 완료하는 데 걸리는 시간을 인식하지 않고도 이러한 작업을 수행 할 수 있기를 원합니다.

어떤 제안이라도 대단히 감사 할 것입니다.

해결법

  1. ==============================

    1.

    리눅스 머신에서 이것을 실행한다고 가정하면, 나는 항상 다음과 같이 처리했다.

    exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));
    

    이 명령은 $ cmd 명령을 실행하고 명령 출력을 $ outputfile로 재지 정하고 프로세스 ID를 $ pidfile에 기록합니다.

    이를 통해 프로세스가 수행중인 작업과 실행중인 작업을 쉽게 모니터링 할 수 있습니다.

    function isRunning($pid){
        try{
            $result = shell_exec(sprintf("ps %d", $pid));
            if( count(preg_split("/\n/", $result)) > 2){
                return true;
            }
        }catch(Exception $e){}
    
        return false;
    }
    
  2. ==============================

    2.

    어떤 언어 (php / bash / perl / etc)가 편리한 지 서버 측 스크립트로 프로세스를 작성한 다음 PHP 스크립트의 프로세스 제어 함수에서 호출하십시오.

    이 함수는 표준 io가 출력 스트림으로 사용되는지 여부를 감지하고 반환 값이 설정되면 반환 값을 설정합니다.

    Proc_Close (Proc_Open ("./command --foo=1 &", Array (), $foo));
    

    필자는 커맨드 라인에서 "sleep 25s"명령어를 사용하여 신속하게 테스트했으며, 매력처럼 작동했습니다.

    (답변은 여기에 있습니다)

  3. ==============================

    3.

    Windows에서이 기능을 테스트하는 간단한 예제를 추가하고 싶습니다.

    다음 두 파일을 만들고 웹 디렉토리에 저장하십시오.

    foreground.php :

    <?php
    
    ini_set("display_errors",1);
    error_reporting(E_ALL);
    
    echo "<pre>loading page</pre>";
    
    function run_background_process()
    {
        file_put_contents("testprocesses.php","foreground start time = " . time() . "\n");
        echo "<pre>  foreground start time = " . time() . "</pre>";
    
        // output from the command must be redirected to a file or another output stream 
        // http://ca.php.net/manual/en/function.exec.php
    
        exec("php background.php > testoutput.php 2>&1 & echo $!", $output);
    
        echo "<pre>  foreground end time = " . time() . "</pre>";
        file_put_contents("testprocesses.php","foreground end time = " . time() . "\n", FILE_APPEND);
        return $output;
    }
    
    echo "<pre>calling run_background_process</pre>";
    
    $output = run_background_process();
    
    echo "<pre>output = "; print_r($output); echo "</pre>";
    echo "<pre>end of page</pre>";
    ?>
    

    background.php :

    <?
    file_put_contents("testprocesses.php","background start time = " . time() . "\n", FILE_APPEND);
    sleep(10);
    file_put_contents("testprocesses.php","background end time = " . time() . "\n", FILE_APPEND);
    ?>
    

    위의 파일을 만든 디렉터리에 IUSR에 쓰기 권한을 부여하십시오.

    READ 및 EXECUTE C : \ Windows \ System32 \ cmd.exe에 IUSR 권한을 부여하십시오.

    웹 브라우저에서 foreground.php를 누르십시오.

    다음은 출력 배열의 현재 타임 스탬프 및 로컬 리소스와 함께 브라우저에 렌더링되어야합니다.

    loading page
    calling run_background_process
      foreground start time = 1266003600
      foreground end time = 1266003600
    output = Array
    (
        [0] => 15010
    )
    end of page
    

    위의 파일들이 저장된 것과 같은 디렉토리에 testoutput.php가 나타나야하며 비어 있어야합니다

    위의 파일들이 저장된 것과 같은 디렉토리에 testprocesses.php가 나타나야하며 현재 타임 스탬프가있는 다음 텍스트가 포함되어 있어야합니다.

    foreground start time = 1266003600
    foreground end time = 1266003600
    background start time = 1266003600
    background end time = 1266003610
    
  4. ==============================

    4.

    이 명령을 명령에 추가하려고 할 수 있습니다.

    >/dev/null 2>/dev/null &
    

    예.

    shell_exec('service named reload >/dev/null 2>/dev/null &');
    
  5. ==============================

    5.

    PHP 페이지가 완료되기를 기다리지 않고 백그라운드에서 무언가를해야한다면 wget 명령으로 "호출 된"다른 PHP 스크립트를 사용할 수 있습니다. 이 배경 PHP 스크립트는 시스템의 다른 PHP 스크립트와 마찬가지로 권한으로 실행됩니다.

    다음은 gnuwin32 패키지의 wget을 사용하는 Windows의 예입니다.

    예를 들어 배경 코드 (test-proc-bg.php 파일) ...

    sleep(5);   // some delay
    file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file
    

    전경 스크립트, 하나의 호출 ...

    $proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
    $proc = popen($proc_command, "r");
    pclose($proc);
    

    이 작업을 제대로 수행하려면 popen / pclose를 사용해야합니다.

    wget 옵션 :

    -q    keeps wget quiet.
    -O -  outputs to stdout.
    -b    works on background
    
  6. ==============================

    6.

    글쎄, 조금 빠르고 사용하기 쉬운 버전을 찾았습니다.

    shell_exec('screen -dmS $name_of_screen $command'); 
    

    작동합니다.

  7. ==============================

    7.

    다음은 PHP에서 백그라운드 프로세스를 시작하는 함수입니다. 마지막으로 많은 접근법과 매개 변수를 읽고 테스트 한 후에 Windows에서도 실제로 작동합니다.

    function LaunchBackgroundProcess($command){
      // Run command Asynchroniously (in a separate thread)
      if(PHP_OS=='WINNT' || PHP_OS=='WIN32' || PHP_OS=='Windows'){
        // Windows
        $command = 'start "" '. $command;
      } else {
        // Linux/UNIX
        $command = $command .' /dev/null &';
      }
      $handle = popen($command, 'r');
      if($handle!==false){
        pclose($handle);
        return true;
      } else {
        return false;
      }
    }
    

    참고 1 : Windows에서는 / B 매개 변수를 다른 위치에서 사용하지 마십시오. 프로세스가 시작 명령 자체와 동일한 콘솔 창을 실행하도록하여 프로세스가 동 기적으로 처리되도록합니다. 별도의 스레드에서 (비동기 적으로) 프로세스를 실행하려면 / B를 사용하지 마십시오.

    참고 2 : 명령이 따옴표로 묶인 경로이면 빈 따옴표가 필요합니다 ( ""). start 명령은 첫 번째 인용 된 매개 변수를 창 제목으로 해석합니다.

  8. ==============================

    8.

    별도의 프로세스를 포크하고 백그라운드에서 복사본을 실행할 수 있습니까? 필자는 PHP를 사용한 지 오래되었지만 pcntl-fork 함수는 유망 해 보인다.

  9. ==============================

    9.

    Resque와 같은 대기열 처리 시스템을 사용해보십시오. 그런 다음 정보를 처리하는 작업을 생성하고 "처리 중"이미지를 사용하여 매우 빨리 반환 할 수 있습니다. 이 방법을 사용하면 언제 끝나는 지 알 수 없습니다.

    이 솔루션은 전면 시스템이 과도한 작업을 수행하지 않도록 사용자 요청을 처리 할 수있는 대규모 응용 프로그램 용입니다. 따라서 파일 및 폴더와 같은 물리적 데이터로 작동하거나 작동하지 않을 수도 있지만보다 복잡한 논리 또는 기타 비동기 작업 (예 : 새 등록 메일)을 처리하는 데는 매우 유용하고 확장 성이 좋습니다.

  10. ==============================

    10.

    이 기능을 사용하여 백그라운드에서 프로그램을 실행하십시오. 그것은 크로스 플랫폼이며 완벽하게 사용자 정의 할 수 있습니다.

    <?php
    function startBackgroundProcess(
        $command,
        $stdin = null,
        $redirectStdout = null,
        $redirectStderr = null,
        $cwd = null,
        $env = null,
        $other_options = null
    ) {
        $descriptorspec = array(
            1 => is_string($redirectStdout) ? array('file', $redirectStdout, 'w') : array('pipe', 'w'),
            2 => is_string($redirectStderr) ? array('file', $redirectStderr, 'w') : array('pipe', 'w'),
        );
        if (is_string($stdin)) {
            $descriptorspec[0] = array('pipe', 'r');
        }
        $proc = proc_open($command, $descriptorspec, $pipes, $cwd, $env, $other_options);
        if (!is_resource($proc)) {
            throw new \Exception("Failed to start background process by command: $command");
        }
        if (is_string($stdin)) {
            fwrite($pipes[0], $stdin);
            fclose($pipes[0]);
        }
        if (!is_string($redirectStdout)) {
            fclose($pipes[1]);
        }
        if (!is_string($redirectStderr)) {
            fclose($pipes[2]);
        }
        return $proc;
    }
    

    명령이 시작된 후, 기본적으로이 함수는 실행중인 프로세스의 stdin과 stdout을 닫습니다. $ redirectStdout 및 $ redirectStderr 인수를 통해 프로세스 출력을 일부 파일로 리디렉션 할 수 있습니다.

    Windows 사용자 참고 사항 : stdout / stderr을 nul 장치로 리디렉션 할 수있는 방법은 없습니다. 불행히도 당신은 그것을 할 수 없습니다 :

    startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');
    

    따라서 stderr / stdin을 유효한 파일로 리디렉션해야합니다. 그렇지 않으면 stderr / stdout 디스크립터가 필요하지 않습니다.

    * nix 사용자를위한 메모 :

    1) 실제 PID를 얻으려면 exec 셸 명령을 사용하십시오.

    $proc = startBackgroundProcess('exec ping yandex.com -c 15', null, '/dev/null', '/dev/null');
    print_r(proc_get_status($proc));
    

    2) 프로그램의 입력에 일부 데이터를 전달하려면 $ stdin 인수를 사용하십시오.

    startBackgroundProcess('cat > input.txt', "Hello world!\n");
    
  11. ==============================

    11.

    백그라운드 프로세스를 시작하는 대신 트리거 파일을 만들고 cron이나 autosys와 같은 스케줄러를 사용하여 트리거 파일을 찾아서 트리거하는 스크립트를 정기적으로 실행하는 방법은 무엇입니까? 트리거는 명령 또는 원시 명령을 포함 할 수 있습니다 (더 좋지만 쉘 스크립트로 만드십시오).

  12. ==============================

    12.

    PHP를 사용하는 경우 pcntl_fork를 사용하여이 작업을 수행하는 훨씬 쉬운 방법이 있습니다.

    http://www.php.net/manual/en/function.pcntl-fork.php

  13. ==============================

    13.

    fast_cgi_finish_request ()를 많이 사용하고 있습니다.

    클로저와 결합하여 register_shutdown_function ()

    $message ='job executed';
    $backgroundJob = function() use ($message) {
         //do some work here
        echo $message;
    }
    

    그런 다음 종료 전에이 클로저를 등록하십시오.

    register_shutdown_function($backgroundJob);
    

    마지막으로 응답이 클라이언트에 전송되면 클라이언트에 대한 연결을 닫고 PHP 프로세스로 계속 작업 할 수 있습니다.

    fast_cgi_finish_request();
    

    클로저는 fast_cgi_finish_request 후에 실행됩니다.

    $ 메시지는 언제든지 표시되지 않습니다. 그리고 원하는만큼 클로저를 등록 할 수 있지만 스크립트 실행 시간에주의하십시오. 이것은 PHP가 Fast CGI 모듈로 실행되는 경우에만 작동합니다 (맞습니까?)

  14. ==============================

    14.

    Windows와 Linux 모두를위한 효과적인 솔루션입니다. 나의 github 페이지에서 더 많은 것을 찾으십시오.

    function run_process($cmd,$outputFile = '/dev/null', $append = false){
                        $pid=0;
                    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                            $cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
                            $handle = popen("start /B ". $cmd, "r");
                            $read = fread($handle, 200); //Read the output 
                            $pid=substr($read,strpos($read,'=')+1);
                            $pid=substr($pid,0,strpos($pid,';') );
                            $pid = (int)$pid;
                            pclose($handle); //Close
                    }else{
                        $pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
                    }
                        return $pid;
                }
                function is_process_running($pid){
                    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                            //tasklist /FI "PID eq 6480"
                        $result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
                        if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
                            return true;
                        }
                    }else{
                        $result = shell_exec(sprintf('ps %d 2>&1', $pid));
                        if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
                            return true;
                        }
                    }
                    return false;
                }
                function stop_process($pid){
                        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                                $result = shell_exec('taskkill /PID '.$pid );
                            if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
                                return true;
                            }
                        }else{
                                $result = shell_exec(sprintf('kill %d 2>&1', $pid));
                            if (!preg_match('/No such process/', $result)) {
                                return true;
                            }
                        }
                }
    
  15. ==============================

    15.

    PHP 스크립팅은 다른 데스크톱 응용 프로그램 개발 언어와 다릅니다. 데스크탑 응용 프로그램 언어에서는 백그라운드 프로세스를 실행하기 위해 데몬 스레드를 설정할 수 있지만 PHP에서는 사용자가 페이지를 요청할 때 프로세스가 발생합니다. 그러나 PHP 스크립트가 실행하는 서버의 cron 작업 기능을 사용하여 백그라운드 작업을 설정할 수 있습니다.

  16. ==============================

    16.

    Windows를 사용하는 사용자는 다음을 참조하십시오.

    참조 : http://php.net/manual/en/function.exec.php#43917

    배경에서 최소화 된 Notepad.exe를 시작하십시오.

    <?php 
    $WshShell = new COM("WScript.Shell"); 
    $oExec = $WshShell->Run("notepad.exe", 7, false); 
    ?> 
    

    백그라운드에서 보이지 않는 쉘 명령을 시작하십시오.

    <?php 
    $WshShell = new COM("WScript.Shell"); 
    $oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false); 
    ?> 
    

    스크립트를 계속하기 전에 MSPaint를 최대화하고 닫을 때까지 기다리십시오.

    <?php 
    $WshShell = new COM("WScript.Shell"); 
    $oExec = $WshShell->Run("mspaint.exe", 3, true); 
    ?> 
    

    Run () 메서드에 대한 자세한 내용은 다음을 참조하십시오. http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp

    수정 된 URL :

    위의 링크가 더 이상 존재하지 않으므로 https://technet.microsoft.com/en-us/library/ee156605.aspx로 이동하십시오.

  17. ==============================

    17.

    나는 그것이 100 년 된 포스트 다. 그러나 어떻게해서든지, 누군가 그것이 유용 할 것 같다고 생각했다. 다음과 같이 백그라운드에서 실행해야하는 URL을 가리키는 페이지의 어딘가에 보이지 않는 이미지를 넣을 수 있습니다.

  18. from https://stackoverflow.com/questions/45953/php-execute-a-background-process by cc-by-sa and MIT lisence