it-gundan.com

PHP 응용 프로그램에서 어떻게 멀티 스레딩을 사용할 수 있습니까?

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

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

366
Steve Obbayi

PHP에서 다중 스레딩이 가능합니다.

네, _threads 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);
}
391
Baba

왜 당신은 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]);
    }
}
34
masterb

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

Curl의 timeout 설정을 1로 설정하고 서로 연관시키고 자하는 프로세스에 대해 동일한 session_id를 사용하면 아래 예 에서처럼 세션 변수와 통신 할 수 있습니다. 이 방법을 사용하면 브라우저를 닫을 수도 있고 동시 프로세스가 서버에 계속 존재할 수도 있습니다.

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

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

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);
18
Ricardo

당신이 스레드 할 수없는 동안, 당신은 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을 사용하여 관리를위한 함수를 등록하고 깨끗한 종료를 할 수 있습니다.

11
J.D. Fitz.Gerald

이 질문은 오래된 질문이지만 사람들이 검색하는 경우 C 언어로 작성된 PECL 확장이 있으며 현재 PHP 멀티 스레딩 기능을 제공합니다. 여기에 있습니다 https : // github .com/krakjoe/pthreads

8
JasonDavis

스레드를 사용하는 것은 pthreads PECL 확장자로 가능하다.

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

8
pinkal vansia

스레딩을 시뮬레이트 할 수 있습니다. PHP는 popen (또는 proc_open)을 통해 백그라운드 프로세스를 실행할 수 있습니다. 이러한 프로세스는 stdin 및 stdout을 통해 통신 할 수 있습니다. 물론 그 프로세스 자체가 PHP 프로그램이 될 수 있습니다. 아마 당신이 얻는만큼 가깝습니다.

5
Pete

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

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

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

보안상의 이유로 디폴트로 exec ()가 비활성화되어있는 공유 호스팅 서버가 상당수 있다고 생각합니다. 그러나 시도해 볼만한 가치가 있습니다.

5
Adam Hopkinson

Pcntl_fork는 어떻습니까?

예제 페이지를 확인하십시오 : PHP pcntl_fork

3
Jarrod

당신이하고자하는 것에 따라 curl_multi를 사용하여 그것을 달성 할 수도 있습니다.

3
Sheldmandu

이 방법은 오래되었다는 것을 알지만, 당신은 http://phpthreadlib.sourceforge.net/ 을 볼 수 있습니다.

그것은 양방향 스레드 간 통신을 지원하고 자식 스레드를 없애기위한 보호 기능을 내장하고 있습니다 (고아 방지).

3
Unsigned

pcntl_fork 안전 모드 가 켜져 있으면 웹 서버 환경에서 작동하지 않습니다. 이 경우 PHP CLI 버전에서만 작동합니다.

2
Stilero

다음 옵션 중 하나를 선택할 수 있습니다.

  1. multi_curl
  2. 하나는 같은 시스템 명령을 사용할 수 있습니다.
  3. 이상적인 시나리오는 C 언어로 스레딩 함수를 만들고 PHP에서 컴파일/구성하는 것입니다. 이제 그 함수는 PHP의 함수가 될 것입니다.
2
Manoj Donga

PECL pthreads가 2.0.0 이상이므로 Thread 클래스 를 사용할 수 있습니다.

2
Dhananjay Kashyap

현재 의견을 쓰는 시점에서 PHP 스레드에 관해서는 알지 못합니다. 여기에 대한 해결책을 찾으러 왔지만 한 가지 해결 방법은 웹 서버로부터 요청을받는 PHP 프로그램이 결과를 저장하는 콘솔 어플리케이션에 전체 응답 공식을 위임하는 것입니다. 콘솔 응용 프로그램을 시작한 PHP 프로그램은 바이너리 파일에받은 바이너리 파일을 수신 된 요청에 대한 응답으로 바이트 단위로 반환합니다. 콘솔 응용 프로그램은 OpenMP를 사용하는 C++ 프로그램을 포함하여 적절한 스레딩 지원을 포함하여 서버에서 실행되는 모든 프로그래밍 언어로 작성할 수 있습니다.

신뢰할 수없고, 지저분한 속임수 중 하나는 PHP를 사용하여 콘솔 응용 프로그램 "uname"을 실행하는 것입니다.

uname -a

해당 콘솔 명령의 출력을 HTML 출력에 인쇄하여 서버 소프트웨어의 정확한 버전을 찾으십시오. 그런 다음 VirtualBox 인스턴스에 정확히 같은 버전의 소프트웨어를 설치하고, 원하는 모든 자체 포함, 바람직하게는 정적 바이너리를 컴파일 및 어셈블하여 서버에 업로드하십시오. 그 시점부터 PHP 어플리케이션은 적절한 멀티 스레딩이있는 콘솔 어플리케이션의 역할에서 바이너리를 사용할 수 있습니다. 서버 관리자가 필요한 모든 프로그래밍 언어 구현을 서버에 설치하지 않은 상황에 대한 더럽고 신뢰할 수없는 해결 방법입니다. 조심해야 할 점은 PHP 애플리케이션이 콘솔 애플리케이션을 수신하는 모든 요청에서/exit/get_killed가 종료된다는 것입니다.

호스팅 서비스 관리자가 이러한 서버 사용 패턴을 어떻게 생각하는지에 관해서는 문화로 귀결됩니다. 북유럽에서는 서비스 제공 업체가 무엇을 제공했는지, 그리고 콘솔 명령의 실행이 허용되고 맬웨어가 아닌 파일의 업로드가 허용되고 서비스 제공 업체가 몇 분 또는 30 초 후에 서버 프로세스를 종료 할 수있는 권리가있는 경우 , 호스팅 서비스 관리자는 적절한 불만을 제기하기위한 어떠한 주장도하지 않습니다. 미국과 서유럽에서는 상황/문화가 매우 다르므로 호스팅 서비스 제공 업체가 미국 및/또는 서유럽에서 위의 트릭을 사용하는 호스팅 서비스 클라이언트를 제공하는 것을 거부 할 가능성이 높습니다. 미국 호스팅 서비스에 대한 개인적인 경험을 바탕으로 서유럽 호스팅 서비스에 대해 다른 사람들에게 들었던 것만 큼 생각하면됩니다. 현재의 의견 (2018_09_01)을 쓰는 시점에서 저는 남유럽 호스팅 서비스 제공 업체 인 남유럽 네트워크 관리자의 문화적 규범에 대해서는 알지 못합니다.

0
Martin Vahi