[php] PHP 애플리케이션에서 멀티 스레딩을 사용하는 방법

PHP에서 멀티 스레드 모델을 실제로 구현하거나 시뮬레이션하는 방법으로 구현하는 현실적인 방법이 있습니까? 얼마 전에 운영 체제가 다른 PHP 실행 파일 인스턴스를로드하고 다른 동시 프로세스를 처리하도록 강제 할 수 있다는 제안이있었습니다.

이 문제는 PHP 코드 실행이 완료되면 PHP 인스턴스에서 PHP 인스턴스를 종료 할 수있는 방법이 없기 때문에 PHP 인스턴스 실행이 메모리에 남아 있다는 것입니다. 따라서 여러 스레드를 시뮬레이트하는 경우 어떻게 될지 상상할 수 있습니다. 그래서 여전히 PHP 내에서 멀티 스레딩을 효과적으로 수행하거나 시뮬레이션 할 수있는 방법을 찾고 있습니다. 어떤 아이디어?



답변

PHP에서 멀티 스레딩 가능

예, pthreads를 사용 하여 PHP에서 멀티 스레딩을 수행 할 수 있습니다

에서 PHP를 문서 :

pthreads는 PHP에서 멀티 스레딩에 필요한 모든 도구를 제공하는 객체 지향 API입니다. PHP 응용 프로그램은 스레드, 작업자 및 스레드 개체를 생성, 읽기, 쓰기, 실행 및 동기화 할 수 있습니다.

경고 : pthreads 확장은 웹 서버 환경에서 사용할 수 없습니다. 따라서 PHP의 스레딩은 CLI 기반 응용 프로그램에만 남아 있어야합니다.

간단한 테스트

#!/usr/bin/php
<?php
class AsyncOperation extends Thread {

    public function __construct($arg) {
        $this->arg = $arg;
    }

    public function run() {
        if ($this->arg) {
            $sleep = mt_rand(1, 10);
            printf('%s: %s  -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
            sleep($sleep);
            printf('%s: %s  -finish' . "\n", date("g:i:sa"), $this->arg);
        }
    }
}

// Create a array
$stack = array();

//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
    $stack[] = new AsyncOperation($i);
}

// Start The Threads
foreach ( $stack as $t ) {
    $t->start();
}

?>

첫 실행

12:00:06pm:     A  -start -sleeps 5
12:00:06pm:     B  -start -sleeps 3
12:00:06pm:     C  -start -sleeps 10
12:00:06pm:     D  -start -sleeps 2
12:00:08pm:     D  -finish
12:00:09pm:     B  -finish
12:00:11pm:     A  -finish
12:00:16pm:     C  -finish

두 번째 실행

12:01:36pm:     A  -start -sleeps 6
12:01:36pm:     B  -start -sleeps 1
12:01:36pm:     C  -start -sleeps 2
12:01:36pm:     D  -start -sleeps 1
12:01:37pm:     B  -finish
12:01:37pm:     D  -finish
12:01:38pm:     C  -finish
12:01:42pm:     A  -finish

실제 예

error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
    public $url;
    public $data;

    public function __construct($url) {
        $this->url = $url;
    }

    public function run() {
        if (($url = $this->url)) {
            /*
             * If a large amount of data is being requested, you might want to
             * fsockopen and read using usleep in between reads
             */
            $this->data = file_get_contents($url);
        } else
            printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
    }
}

$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
    printf("Request took %f seconds to start ", microtime(true) - $t);
    while ( $g->isRunning() ) {
        echo ".";
        usleep(100);
    }
    if ($g->join()) {
        printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
    } else
        printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}


답변

popen 을 사용하지 않습니까?

for ($i=0; $i<10; $i++) {
    // open ten processes
    for ($j=0; $j<10; $j++) {
        $pipe[$j] = popen('script2.php', 'w');
    }

    // wait for them to finish
    for ($j=0; $j<10; ++$j) {
        pclose($pipe[$j]);
    }
}


답변

스레딩은 기본 PHP에서 사용할 수 없지만 HTTP 요청을 비동기 호출로 사용하여 동시 프로그래밍이 가능합니다.

curl의 시간 초과 설정을 1로 설정하고 서로 연결하려는 프로세스에 동일한 session_id를 사용하면 아래 예와 같이 세션 변수와 통신 할 수 있습니다. 이 방법을 사용하면 브라우저를 닫을 수 있으며 동시 프로세스는 여전히 서버에 존재합니다.

다음과 같이 올바른 세션 ID를 확인하는 것을 잊지 마십시오 :

http : //localhost/test/verifysession.php? sessionid = [ 올바른 id]

startprocess.php

$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];

process1.php

set_time_limit(0);

if ($_REQUEST["sessionid"])
   session_id($_REQUEST["sessionid"]);

function checkclose()
{
   global $_SESSION;
   if ($_SESSION["closesession"])
   {
       unset($_SESSION["closesession"]);
       die();
   }
}

while(!$close)
{
   session_start();
   $_SESSION["test"] = rand();
   checkclose();
   session_write_close();
   sleep(5);
}

verifysession.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
var_dump($_SESSION);

closeprocess.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);


답변

스레드 할 수는 없지만 PHP에는 어느 정도 프로세스 제어가 있습니다. 여기서 유용한 두 가지 기능 세트는 다음과 같습니다.

공정 제어 기능
http://www.php.net/manual/en/ref.pcntl.php

POSIX 기능
http://www.php.net/manual/en/ref.posix.php

pcntl_fork로 프로세스를 포크하여 자식의 PID를 반환 할 수 있습니다. 그런 다음 posix_kill을 사용하여 해당 PID를 폐기 할 수 있습니다.

즉, 부모 프로세스를 종료하면 자식 프로세스에 신호를 보내서 죽도록 지시해야합니다. PHP 자체가이를 인식하지 못하는 경우이를 관리하는 기능을 등록하고 pcntl_signal을 사용하여 완전히 종료 할 수 있습니다.


답변

pthreads PECL 확장으로 스레드 사용 가능

http://www.php.net/manual/en/book.pthreads.php


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 검색하는 사람들을 위해 지금 PHP 멀티 스레딩 기능을 제공하는 C로 작성된 PECL 확장이 있으며 여기에 있습니다.


답변

exec ()를 사용하여 명령 행 스크립트 (예 : 명령 행 php)를 실행할 수 있으며 출력을 파일로 파이프하면 명령이 완료 될 때까지 스크립트가 대기하지 않습니다.

PHP CLI 구문을 기억할 수는 없지만 다음과 같은 것을 원할 것입니다.

exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");

꽤 많은 공유 호스팅 서버가 보안상의 이유로 기본적으로 exec ()가 비활성화되어 있다고 생각하지만 시도해 볼 가치가 있습니다.