PHP中的多个异步函数调用

PHP中的多个异步函数调用,php,symfony,asynchronous,parallel-processing,reactphp,Php,Symfony,Asynchronous,Parallel Processing,Reactphp,我使用Symfony 3和library来控制我的所有功能,我需要异步地执行对同一个函数的多个调用(subFunction())。 我有两个项目(项目1和项目2): 项目1代码: /** * Loop an array of urls and call sub function. **/ public function startFunction() { $finalResponse = []; $urls = ['www.google.es', 'www.github.com', 'w

我使用Symfony 3和library来控制我的所有功能,我需要异步地执行对同一个函数的多个调用(
subFunction()
)。 我有两个项目(项目1和项目2):

项目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;
}
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;
}

}
项目2代码:

/**
* 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;
}
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;
}

}
问题是,在每次调用
子函数($url)
时,程序都会停止,直到子函数得到响应为止,但我需要异步执行此操作,因为此子函数可能需要很多秒。 因此,我希望同时启动所有
子函数($url)
调用,并异步获取所有响应


有可能解决这个问题吗?谢谢。

首先,应用程序中只能运行一个循环。 其次,必须运行循环:

您应该创建应用程序,然后注册所有服务和事件,启动循环并使其作为服务器运行

$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.

首先,一个应用程序中只能运行一个循环。 其次,必须运行循环:

您应该创建应用程序,然后注册所有服务和事件,启动循环并使其作为服务器运行

$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.

如果
子函数
是阻塞函数调用,则有多个选项

重写
子功能
以使用非阻塞I/O

这可能有效,也可能无效,这取决于函数正在执行的操作。如果函数主要是等待I/O,比如等待HTTP响应,那么这可能是更简单的方法,但这完全取决于需要重写的代码的复杂性

ReactPHP提供了一个HTTP客户端,它使用非阻塞I/O执行HTTP请求并接收您已经在使用的响应

使用多重处理

如果
子函数
受CPU限制,或者您尝试使用的协议不存在非阻塞驱动程序,则可以使用多处理在另一个进程中执行该函数,而不阻塞主事件循环

ReactPHP有一个子进程库,但我目前还不知道ReactPHP有一个库可以使并行处理像使用一样简单。虽然该库是基于的,但在Amp之上存在使用任何PHP库的方法,因此您可以继续使用当前的库

使用,它构建在
amhp/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));

如果
子函数
是阻塞函数调用,则有多个选项

重写
subFunction
使用非阻塞I/O

这可能有效,也可能无效,这取决于函数正在执行的操作。如果函数主要是等待I/O,比如等待HTTP响应,那么这可能是更简单的方法,但这完全取决于需要重写的代码的复杂性

ReactPHP提供了一个HTTP客户端,它使用非阻塞I/O执行HTTP请求并接收您已经在使用的响应

使用多重处理

如果
子函数
受CPU限制,或者您尝试使用的协议不存在非阻塞驱动程序,则可以使用多处理在另一个进程中执行该函数,而不阻塞主事件循环

ReactPHP有一个子进程库,但我目前还不知道ReactPHP有一个库可以使并行处理像使用一样简单。虽然该库是基于的,但在Amp之上存在使用任何PHP库的方法,因此您可以继续使用当前的库

使用,它构建在
amhp/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));

在我的
startFunction()
主函数中使用
$loop->run()
并在
子函数()中返回ReactPHP承诺,我终于解决了问题。但是,我将尝试重写代码以使用Guzzle Async。。谢谢。我终于在我的
startFunction()
主函数中使用
$loop->run()
,并在
子函数()中返回ReactPHP承诺,解决了我的问题。但是,我将尝试重写代码以使用Guzzle Async。。谢谢-我从来没有使用过AMPP/并行函数,但我会读一读。。看起来真的很有趣。谢谢-我从来没有使用过AMPP/并行函数,但我会读一读。。看起来真的很有趣。谢谢