2017-12-12 37 views
0

Symfony 3 및 ReactPHP 라이브러리를 사용하여 모든 기능을 제어하고 동일한 함수 (subFunction() 코드) 비동기 적으로을 여러 번 호출해야합니다. 나는이 개 프로젝트 (프로젝트 1 및 프로젝트 2)가 :PHP에서 여러 함수 호출을 비동기 적으로 호출

프로젝트 1 코드 :

/** 
* Loop an array of urls and call sub function. 
**/ 
public function startFunction() { 
    $finalResponse = []; 
    $urls = ['www.google.es', 'www.github.com', 'www.bitbucket.org']; 

    foreach ($urls as $url) { 
    $res = $this->subFunction($url); // subfunction call (**IT MAY TAKE A LONG TIME !!**) 
    $finalResponse[] = $res; 
} 

return $finalResponse; 
} 

/** 
* Uses Factory loop to get the Promise returned by finalRequest function. 
**/ 
private function subFunction($url) { 
    $loop = \React\EventLoop\Factory::create(); 
    $classA = new Project2\ClassA(); 
    $finalResponse = null; 

    // project 2 function call 
    $classA->finalRequest($url)->then(function($response) use( 
    &$finalResponse 
) { 
    $finalResponse = $response; 
    }) 

    return $finalResponse; 
} 

프로젝트 코드 2 :

classA { 

/** 
* Makes an React\HttpClient request (GET) to sent url and return his value inside a Promise. 
**/ 
public function finalRequest($url) { 
    $generalDeferred = new Deferred(); 
    $generalPromise = $generalDeferred->promise(); 

    // make React\HttpClient request 
    $request = $client->request('GET', $url); 
    $request->on('response', function ($response) use($generalDeferred) { 
    $response->on('data', function ($response) { 
     $generalDeferred->resolve($response); 
     }); 
    }); 
    $request->end(); 

    return $generalPromise; 
} 

} 

문제가 있음을 모든 subFunction($url) 통화는 프로그램은 하위 함수가 응답을받을 때까지 멈추지 만,이 하위 함수는 많은 시간이 걸릴 수 있기 때문에 비동기 적으로이 작업을 수행해야합니다. 그래서 모든 subFunction($url) 호출을 동시에 시작하고 모든 응답을 비동기 적으로 가져오고 싶습니다.

이 문제를 해결할 수 있습니까? 감사.

답변

2

우선 앱에서 하나의 루프 만 실행할 수 있습니다. 두 번째로 루프를 실행해야합니다. https://reactphp.org/event-loop/

앱을 만든 다음 모든 서비스 및 이벤트를 등록하고 루프를 시작한 다음 서버로 실행해야합니다.

$loop = React\EventLoop\Factory::create(); 

$server = stream_socket_server('tcp://127.0.0.1:8080'); 
stream_set_blocking($server, 0); 

$loop->addReadStream($server, function ($server) use ($loop) { 
[...] 
}); 

$loop->addPeriodicTimer(5, function() { 
[...] 
}); 

$loop->run(); <---- you will not execute anything behind this point. 

왜? 나는 목구멍 비동기를 사용하는 것이 좋습니다 당신은 루프의 수행 사용하기 위해

public function run() 
{ 
    $this->running = true; 
    while ($this->running) { <------------------------------ 
     $this->futureTickQueue->tick(); 
     $flags = EVLOOP_ONCE; 
     if (!$this->running || !$this->futureTickQueue->isEmpty()) { 
      $flags |= EVLOOP_NONBLOCK; 
     } elseif (!$this->streamEvents && !$this->timerEvents->count()) { 
      break; 
     } 
     event_base_loop($this->eventBase, $flags); 
    } 
} 

https://github.com/reactphp/event-loop/blob/master/src/ExtLibeventLoop.php#L196 : 당신의 subFunction이 차단 함수 호출 인 경우 http://docs.guzzlephp.org/en/stable/faq.html

$finalResponse = []; 
$promises = []; 
$urls = ['www.google.es', 'www.github.com', 'www.bitbucket.org']; 
foreach ($urls as $index => $url) { 
    $promise = $client->requestAsync('GET', $url); 
    $promise->then(function ($response) use ($index, &$finalResponse) { 
     $finalResponse[$index]=$response; 
    }); 
    $promises[$index]=$promise; 
} 
foreach ($promises as $promise) { 
    $promise->wait(); 
} 
return $finalResponse; 
+0

작동 했습니까? 아무것도 분명히하기 위해 나를 필요로하니? – albert

+0

마침내 내 'startFunction()'main 함수에서'$ loop-> run()'을 사용하고'subFunction()'에서 ReactPHP Promises를 반환하여 문제를 해결했다. 그러나, 나는 Guzzle Async ..를 사용하기 위해 코드를 다시 작성하려고 노력할 것이다. Thankss¡ – Wildchild

1

여러 옵션이 있습니다.

재 작성 subFunction

이 작동 또는 기능이 무엇을하고 있는지에 따라 작동하지 않을 수 있습니다 I/O를 비 차단을 사용합니다. 함수가 주로 HTTP 응답을 기다리는 것과 같은 I/O를 기다리는 경우이 방법이 더 쉬울 수 있지만 코드를 다시 작성해야하는 복잡성에 따라 달라집니다.

ReactPHP는 비 차단 입출력을 사용하여 HTTP 요청을 수행하고 이미 사용중인 응답을 수신하는 HTTP 클라이언트를 제공합니다.

를 사용하여 멀티 프로세싱

당신의 subFunction는 CPU 바인딩하거나, 당신이 실행하는 멀티 프로세싱을 사용하여 사용하려는 프로토콜에 대한 비 차단 드라이버가 존재하지 않는 경우 메인 이벤트 루프를 차단하지 않고 다른 프로세스에서 작동합니다.

ReactPHP 용 하위 프로세스 라이브러리가 있는데, 현재 amphp/parallel처럼 쉽게 병렬 처리를 수행하는 ReactPHP 용 라이브러리를 인식하지 못했습니다.해당 라이브러리는 Amp을 기반으로하지만 a compatibility adapter이 Amp 위에 모든 ReactPHP 라이브러리를 사용하므로 현재 라이브러리를 계속 사용할 수 있습니다.

amphp/parallel-functionsamphp/parallel 위에 작성되며 몇 줄의 코드로 다른 프로세스에서 함수를 간단히 실행할 수 있습니다. 유일한 제한은 전달 된 데이터 (인수 및 반환 값)가 직렬화 가능해야한다는 것입니다.

<?php 

use Amp\Promise; 
use function Amp\ParallelFunctions\parallel; 

$callable = parallel('subFunction'); 

$promise = $callable($arg1, $arg2, $arg3); 

// either yield $promise in a coroutine, 
// or adapt it to a ReactPHP promise, 
// or use Promise\wait for a blocking wait. 

var_dump(Promise\wait($promise)); 
+0

'amphp/parallel-functions'을 한번도 사용하지는 않았지만 나는 그것에 대해 읽을 것이다. 고마워. – Wildchild

+0

나는 내 코드에서 첫 번째 접근 방식을 사용하고있다.;) – Wildchild