Programming

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

procodes 2020. 2. 25. 22:54
반응형

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 확장이 있습니다. 이곳은 https://github.com/krakjoe/pthreads에 있습니다.


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

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

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

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


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


pcntl_fork는 어떻습니까?

예제를 보려면 매뉴얼 페이지를 확인하십시오 : PHP pcntl_fork

<?php

    $pid = pcntl_fork();
    if ($pid == -1) {
        die('could not fork');
    } else if ($pid) {
        // we are the parent
        pcntl_wait($status); //Protect against Zombie children
    } else {
        // we are the child
    }

?>

무엇을하려고하는지에 따라 curl_multi를 사용하여 달성 할 수도 있습니다.


나는 이것이 오래된 방법이라는 것을 알고 있지만 http://phpthreadlib.sourceforge.net/

양방향 스레드 간 통신을 지원하고 자식 스레드를 제거 (고아 방지)하기위한 보호 기능도 내장되어 있습니다.


Thread 클래스는 PECL의 pthreads 정보는 2.0.0을 ≥부터 사용할 수 있습니다.


다음과 같은 옵션이 있습니다.

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

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


현재 의견을 작성하면서 PHP 스레드에 대해 알지 못합니다. 여기에서 답을 직접 찾아 보았지만 한 가지 해결 방법은 웹 서버에서 요청을받는 PHP 프로그램이 전체 답변 형식을 출력, 요청에 대한 답변, 이진 파일을 저장하는 콘솔 응용 프로그램에 위임한다는 것입니다 콘솔 응용 프로그램을 시작한 PHP 프로그램은 이진 파일을 바이트 단위로 수신 된 요청에 대한 응답으로 리턴합니다. 콘솔 응용 프로그램은 OpenMP를 사용하는 C ++ 프로그램을 포함하여 적절한 스레딩을 지원하는 언어를 포함하여 서버에서 실행되는 모든 프로그래밍 언어로 작성할 수 있습니다.

신뢰할 수없고 더럽고 트릭 인 방법 중 하나는 PHP를 사용하여 콘솔 응용 프로그램 "uname"을 실행하는 것입니다.

uname -a

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

호스팅 서비스 관리자가 그러한 서버 사용 패턴에 대해 어떻게 생각하는지에 대해서는 문화로 귀결됩니다. 북유럽에서 서비스 제공 업체는 광고 한 내용을 전달해야하며 콘솔 명령 실행이 허용되고 맬웨어가 아닌 파일의 업로드가 허용 된 경우 서비스 제공 업체는 몇 분 후 또는 30 초 후에 서버 프로세스를 종료 할 수 있습니다 호스팅 서비스 관리자에게는 적절한 불만 제기에 대한 주장이 없습니다. 미국과 서유럽의 상황 / 문화는 매우 다르며 미국 및 / 또는 서유럽에서는 호스팅 서비스 제공 업체가 위에서 설명한 트릭을 사용하는 호스팅 서비스 클라이언트의 서비스 제공을 거부 할 가능성이 크다고 생각합니다. 미국과의 개인적인 경험을 고려할 때 그것은 단지 내 추측입니다. 호스팅 서비스를 제공하고 서유럽 호스팅 서비스에 대해 다른 사람들로부터 들어 본 내용을 제공했습니다. 내 현재 의견을 쓸 때 (2018_09_01) 나는 남유럽 네트워크 서비스 관리자 인 남유럽 호스팅 서비스 제공 업체의 문화 규범에 대해 아무것도 모른다.


내가 뭔가를 놓친 것일 수도 있지만 exec는 Windows에서 다음과 같이 Windows에서 사용하는 비동기식으로 작동하지 않았으며 매력처럼 작동했습니다.)

$script_exec = "c:/php/php.exe c:/path/my_ascyn_script.php";

pclose(popen("start /B ". $script_exec, "r"));

멀티 스레딩은 여러 작업 또는 프로세스를 동시에 수행하는 것을 의미합니다. PHP에서 멀티 스레딩을 달성하는 직접적인 방법은 없지만 다음과 같은 방법으로 거의 동일한 결과를 얻을 수 있지만 다음 코드를 사용하여 PHP에서이를 달성 할 수 있습니다.

chdir(dirname(__FILE__));  //if you want to run this file as cron job
 for ($i = 0; $i < 2; $i += 1){
 exec("php test_1.php $i > test.txt &");
 //this will execute test_1.php and will leave this process executing in the background and will go         

 //to next iteration of the loop immediately without waiting the completion of the script in the   

 //test_1.php , $i  is passed as argument .

}

Test_1.php

$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1];  //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert  into  test   set

                id='$i',

                comment='test',

                datetime=NOW() ");

}

이것은 test_1.php를 두 번 동시에 실행하고 두 프로세스가 백그라운드에서 동시에 실행되므로 PHP에서 멀티 스레딩을 얻을 수 있습니다.

이 사람은 정말 좋은 일을 했습니다.

참고 URL : https://stackoverflow.com/questions/70855/how-can-one-use-multi-threading-in-php-applications



반응형