php 协程 异步,在Lumen项目中自定义后置异步协程

上一篇文章介绍了利用yield特性实现后置的MySQL异步查询协程,按照这种“后置执行”的思路,其实还可以实现更多其他的后置异步协程。这里介绍如何自定义一个后置异步协程,将最大开发自由度交由Lumen框架使用者。

CustomAsyncProcess

lumen-swoole-http中已经定义了抽象类CustomAsyncProcess,在处理用户请求时,若是捕获到CustomAsyncProcess类的对象,程序便会按照CustomAsyncProcess对象的指定方法执行。部分代码:

1

2

3

4

5

6

7

8

9

10

11

12<?php

...

$current_value = $last_generator->current();

if ($current_value instanceof CustomAsyncProcess) {

if ($worker->canDoCoroutine()) {

$worker->upCoroutineNum();

return $current_value->runAsyncTask($request, $response, $worker, $this->scheduler, $last_generator);

} else {

return $current_value->runNormalTask($request, $response, $worker, $this->scheduler, $last_generator);

}

}

...

一个简单的后置协程

我们先来实现一个简单的后置协程EasyProcess,继承自CustomAsyncProcess,需要实现两个抽象方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32<?php

namespace App\http\AfterCoroutines;

use BL\SwooleHttp\Service;

use BL\SwooleHttp\Coroutine\SimpleSerialScheduler;

use Generator;

use swoole_http_request as SwooleHttpRequest;

use swoole_http_response as SwooleHttpResponse;

class EasyProcess extends \BL\SwooleHttp\Coroutine\CustomAsyncProcess

{

// 因为有协程数量限制,达到最大协程数量时,会调用runNormalTask方法

public function runNormalTask(SwooleHttpRequest $request, SwooleHttpResponse $response, Service $worker, SimpleSerialScheduler $scheduler, Generator $last_generator)

{

$value = 2;

// 给最后一层生成器,传入$value值,并递归导出整个生成器套层的最终值$final

$final = $this->fullRunScheduler($scheduler, $last_generator, $value);

$http_response = $final;

// 注意:runNormalTask方法中使用makeNormalResponse方法响应用户请求

$this->makeNormalResponse($request, $response, $worker, $http_response);

}

// 没达到最大协程数量时,会调用runAsyncTask方法

public function runAsyncTask(SwooleHttpRequest $request, SwooleHttpResponse $response, Service $worker, SimpleSerialScheduler $scheduler, Generator $last_generator)

{

$value = 1;

// 给最后一层生成器,传入$value值,并递归导出整个生成器套层的最终值$final

$final = $this->fullRunScheduler($scheduler, $last_generator, $value);

$http_response = $final;

// 注意:runAsyncTask方法中使用makeAsyncResponse方法响应用户请求

$this->makeAsyncResponse($request, $response, $worker, $http_response);

}

}

然后就可以在Controller中使用这个后置协程:

1

2

3

4

5

6

7

8

9

10

11

12

13<?php

namespace App\Http\Controllers;

use App\http\AfterCoroutines\EasyProcess;

use App\Http\Controllers\Controller;

class TestController extends Controller

{

public function test()

{

$a = yield new EasyProcess();

response()->json($a);

}

}

当访问TestController@test对应的路由时,得到的返回结果有可能是1,也有可能是2,视当时协程数量而定。1或2这个结果在TestController@test层面上是未曾知的,是由EasyProcess这个后置协程产出的。

EasyProcess不算一个异步协程,无论runNormalTask方法或者runAsyncTask方法,都是同步执行的。若想实现异步执行,必须使用Swoole提供的异步客户端,详细请查看Swoole官方文档AsyncIO。

下面介绍如何实现一个后置的异步HTTP客户端协程。

一个后置的异步HTTP客户端协程

假设我们处理某个用户请求时,需要从远端链接http://www.domain.com/api/data获取一些数据,期间可能需要耗时几秒钟,那么怎样用后置异步协程实现来避免阻塞呢?

我们先来实现一个简单的后置协程AysncHttpProcess,继承自CustomAsyncProcess,需要实现两个抽象方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44<?php

namespace App\http\AfterCoroutines;

use BL\SwooleHttp\Service;

use BL\SwooleHttp\Coroutine\SimpleSerialScheduler;

use Generator;

use swoole_http_request as SwooleHttpRequest;

use swoole_http_response as SwooleHttpResponse;

use Swoole\Http2\Client as SwooleHttpClient;

class AysncHttpProcess extends \BL\SwooleHttp\Coroutine\CustomAsyncProcess

{

public function $url;

public function __construct($url)

{

$this->url = $url;

}

// 因为有协程数量限制,达到最大协程数量时,会调用runNormalTask方法

public function runNormalTask(SwooleHttpRequest $request, SwooleHttpResponse $response, Service $worker, SimpleSerialScheduler $scheduler, Generator $last_generator)

{

$data = file_get_contents($this->url);

// 给最后一层生成器,传入$value值,并递归导出整个生成器套层的最终值$final

$final = $this->fullRunScheduler($scheduler, $last_generator, $data);

$http_response = $final;

// 注意:runNormalTask方法中使用makeNormalResponse方法响应用户请求

$this->makeNormalResponse($request, $response, $worker, $http_response);

}

// 没达到最大协程数量时,会调用runAsyncTask方法

public function runAsyncTask(SwooleHttpRequest $request, SwooleHttpResponse $response, Service $worker, SimpleSerialScheduler $scheduler, Generator $last_generator)

{

$client = new SwooleHttpClient();

$caller = $this;

$client->get($this->url, function ($o) use($client, $caller){

$data = $o->body;

// 给最后一层生成器,传入$value值,并递归导出整个生成器套层的最终值$final

$final = $caller->fullRunScheduler($scheduler, $last_generator, $value);

$http_response = $final;

// 注意:runAsyncTask方法中使用makeAsyncResponse方法响应用户请求

$caller->makeAsyncResponse($request, $response, $worker, $http_response);

$client->close();

});

}

}

然后就可以在Controller中使用这个后置协程:

1

2

3

4

5

6

7

8

9

10

11

12

13<?php

namespace App\Http\Controllers;

use App\http\AfterCoroutines\AysncHttpProcess;

use App\Http\Controllers\Controller;

class TestController extends Controller

{

public function test()

{

$a = yield new AysncHttpProcess('http://www.domain.com/api/data');

response()->json($a);

}

}

就这样,在协程数量允许情况下,我们可以使用后置的异步HTTP客户端协程获取远端数据,并且避免了阻塞。

最后

三篇文章:

至此,已经将lumen-swoole-http的设计理念介绍完了,主要是两点:

利用Swoole HTTP服务器运行Lumen项目,提高执行效率;

利用后置异步协程,保持同步编程风格,避免主进程阻塞。

Swoole填补了PHP网络编程的缺陷,引入NodeJS、GoLang等语言的并行执行特性,使用了不同的编程风格。对此,不应该一味抗拒,而是学会融会贯通——学无止境,知识没有界限,PHPer也应该学习其他语言的设计理念,特别是为高并发而生的GoLang。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用PHPLumen开发一个简单的API网关非常方便和快捷。以下是基本步骤: 第一步是安装和设置Lumen框架。可以通过Composer来安装Lumen,并设置好基本配置文件。 接下来,我们需要创建一个API网关的主要路由。可以使用Lumen的路由系统来定义API的路由,将后端服务与客户端请求连接起来。 在定义路由时,可以使用Lumen提供的间件(如Auth间件)对请求进行验证和处理。这些间件可以用来确保请求的安全性和有效性。 接下来,我们需要编写处理API请求的控制器。在控制器,我们可以从请求获取必要的参数,并与后端服务进行通信。可以使用Lumen提供的HTTP客户端(如Guzzle)来与其他API进行通信。 在控制器,可以对请求进行验证和过滤,以确保数据的完整性和安全性。之后,我们可以通过使用Guzzle发送请求到后端服务,并将响应返回给客户端。 最后,我们可以在Lumen使用间件来对响应进行处理和修改。可以使用间件来添加特定的响应头,对响应进行缓存或者修改返回的数据格式等。 可以使用Lumen提供的内置服务器来启动网关,也可以使用其他Web服务器(如Nginx或Apache)来部署和运行API网关。 总结起来,使用PHPLumen开发一个简单的API网关可以通过安装和设置Lumen、定义路由、编写控制器、使用间件等步骤来完成。这样可以实现对客户端请求的验证、处理和转发,连接后端服务并返回响应给客户端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值