Swoole4提供了强大的PHP CSP协程编程模式。底层提供了3个关键词,可以方便地实现各类功能。

关键词

go :创建一个协程

chan :创建一个通道

defer :延迟任务,在协程退出时执行,先进后出

这3个功能底层实现全部为内存操作,没有任何IO资源消耗。就像PHP的Array一样是非常廉价的。如果有需要就可以直接使用。这与socket和file操作不同,后者需要向操作系统申请端口和文件描述符,读写可能会产生阻塞的IO等待。

协程并发

使用go函数可以让一个函数并发地去执行。在编程过程中,如果某一段逻辑可以并发执行,就可以将它放置到go协程中执行。

顺序执行

function test1()

{

sleep(1);

echo "b";

}

function test2()

{

sleep(2);

echo "c";

}

test1();

test2();

执行结果:

htf@LAPTOP-0K15EFQI:~$ time php b1.php

bc

real 0m3.080s

user 0m0.016s

sys 0m0.063s

htf@LAPTOP-0K15EFQI:~$

上述代码中,test1和test2会顺序执行,需要3秒才能执行完成。

并发执行

使用go创建协程,可以让test1和test2两个函数变成并发执行。

Swoole\Runtime::enableCoroutine();

go(function ()

{

sleep(1);

echo "b";

});

go(function ()

{

sleep(2);

echo "c";

});

执行结果:

bchtf@LAPTOP-0K15EFQI:~$ time php co.php

bc

real 0m2.076s

user 0m0.000s

sys 0m0.078s

htf@LAPTOP-0K15EFQI:~$

可以看到这里只用了2秒就执行完成了。

顺序执行耗时等于所有任务执行耗时的总和 :t1+t2+t3...)

并发执行耗时等于所有任务执行耗时的最大值 :max(t1, t2, t3, ...)

协程通信

有了go关键词之后,并发编程就简单多了。与此同时又带来了新问题,如果有2个协程并发执行,另外一个协程,需要依赖这两个协程的执行结果,如果解决此问题呢?

答案就是使用通道(Channel),在Swoole4协程中使用new chan就可以创建一个通道。通道可以理解为自带协程调度的队列。它有两个接口push和pop:

push:向通道中写入内容,如果已满,它会进入等待状态,有空间时自动恢复

pop:从通道中读取内容,如果为空,它会进入等待状态,有数据时自动恢复

使用通道可以很方便地实现并发管理。

$chan = new chan(2);

# 协程1

go (function () use ($chan) {

$result = [];

for ($i = 0; $i < 2; $i++)

{

$result += $chan->pop();

}

var_dump($result);

});

# 协程2

go(function () use ($chan) {

$cli = new Swoole\Coroutine\Http\Client('www.qq.com', 80);

$cli->set(['timeout' => 10]);

$cli->setHeaders([

'Host' => "www.qq.com",

"User-Agent" => 'Chrome/49.0.2587.3',

'Accept' => 'text/html,application/xhtml+xml,application/xml',

'Accept-Encoding' => 'gzip',

]);

$ret = $cli->get('/');

// $cli->body 响应内容过大,这里用 Http 状态码作为测试

$chan->push(['www.qq.com' => $cli->statusCode]);

});

# 协程3

go(function () use ($chan) {

$cli = new Swoole\Coroutine\Http\Client('www.163.com', 80);

$cli->set(['timeout' => 10]);

$cli->setHeaders([

'Host' => "www.163.com",

"User-Agent" => 'Chrome/49.0.2587.3',

'Accept' => 'text/html,application/xhtml+xml,application/xml',

'Accept-Encoding' => 'gzip',

]);

$ret = $cli->get('/');

// $cli->body 响应内容过大,这里用 Http 状态码作为测试

$chan->push(['www.163.com' => $cli->statusCode]);

});

执行结果:

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$ time php co2.php

array(2) {

["www.qq.com"]=>

int(302)

["www.163.com"]=>

int(200)

}

real 0m0.268s

user 0m0.016s

sys 0m0.109s

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$

这里使用go创建了3个协程,协程2和协程3分别请求qq.com和163.com主页。协程1需要拿到Http请求的结果。这里使用了chan来实现并发管理。

协程1循环两次对通道进行pop,因为队列为空,它会进入等待状态

协程2和协程3执行完成后,会push数据,协程1拿到了结果,继续向下执行

延迟任务

在协程编程中,可能需要在协程退出时自动实行一些任务,做清理工作。类似于PHP的register_shutdown_function,在Swoole4中可以使用defer实现。

Swoole\Runtime::enableCoroutine();

go(function () {

echo "a";

defer(function () {

echo "~a";

});

echo "b";

defer(function () {

echo "~b";

});

sleep(1);

echo "c";

});

执行结果:

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$ time php defer.php

abc~b~a

real 0m1.068s

user 0m0.016s

sys 0m0.047s

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$

结语

Swoole4提供的Go + Chan + Defer为PHP带来了一种全新的CSP并发编程模式。灵活使用Swoole4提供的各项特性,可以解决工作中各类复杂功能的设计和开发。

有疑问加站长微信联系(非本文作者)

php defer,PHP 协程:Go + Chan + Defer相关推荐

  1. go 怎么等待所有的协程完成_Go 编程:如何实现协程调度的精准控制

    说起 Go 协程的调度,如果你了解 Go 调度器以及其实现的 G/P/M 模型,当然有助于应用的开发.但是在应用层面上,这些底层的调度原理并不会帮你太多,实现 Go 协程的精准调度得完全靠自己. 问题 ...

  2. go 怎么等待所有的协程完成_Go语言入门必知教程-协程

    Golang中的并发性是指函数独立运行的能力.Goroutines就是能够并发运行的函数,也叫协程,它们是Golang提供作为并发处理操作的方法. 使用go语句创建协程goroutines 要将函数作 ...

  3. mysql 连接查询_Swoole 实战:MySQL 查询器的实现(协程连接池)

    Swoole 实战:MySQL 查询器的实现(协程连接池) 需求分析 本篇我们将通过 Swoole 实现一个自带连接池的 MySQL 查询器: 1. 支持通过链式调用构造并执行 SQL 语句: 2. ...

  4. Golang - 协程池 ants.NewPoolWithFunc使用介绍

    前言 ants是一个高性能的协程池,实现了对大规模goroutine的调度管理.goroutine复用,允许使用者在开发并发程序的时候限制协程数量,复用资源,达到更高效执行任务的效果. 提示:以下是本 ...

  5. Go 学习笔记(25)— 并发(04)[有缓冲/无缓冲通道、WaitGroup 协程同步、select 多路监听通道、close 关闭通道、channel 传参或作为结构体成员]

    1. 无缓冲的通道 无缓冲的通道(unbuffered channel)是指在接收前没有能力保存任何值的通道. 这种类型的通道要求发送 goroutine 和接收 goroutine 同时准备好,才能 ...

  6. golang 协程同步 简介

    目录 协程概念简要理解 为什么要做同步 协程的几种同步方法 Mutex channel WaitGroup 协程概念简要理解 协程类似线程,是一种更为轻量级的调度单位,但协程还是不同于线程的,线程是系 ...

  7. golang context 父子任务同步取消信号 协程调度 简介

    目录 前言 为什么需要context context是什么 context的使用 总结 前言 这篇文章将介绍Golang并发编程中常用到一种编程模式:context.本文将从为什么需要context出 ...

  8. golang goroutine 协程原理

    一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...

  9. golang 数组 最后一个_面试必问:Golang高阶Golang协程实现原理

    1 01 引言 实现并发编程有进程,线程,IO多路复用的方式.(并发和并行我们这里不区分,如果CPU是多核的,可能在多个核同时进行,我们叫并行,如果是单核,需要排队切换,我们叫并发). 1.1 进程和 ...

最新文章

  1. 如何在Matlab中获取函数参数的数目?
  2. dom解析和生成XML文件
  3. linux挂载wondiws目录,linux cifs自动挂载windows硬盘或文件夹
  4. JS调用C#后台函数
  5. redis 零散知识
  6. 看完就能独自把集群搭起来!Hadoop HDFS完全分布式环境搭建以及技术详解
  7. 为什么重写equals时必须重写hashCode方法?
  8. Linux 命令(11)—— col 命令
  9. isp串口下载 stm32_快速入门STM32单片机
  10. XAMPP mysql远程连接
  11. java解压zip异常_zip 文件解压缩问题解决 java.util.zip.ZipException:error in opening zip file | 学步园...
  12. MySQL可视化软件(Navicat)部署与使用
  13. 网易邮箱登录php,PHP模拟登陆163邮箱发邮件及获取通讯录列表的方法
  14. 【图论】 腾讯大战360
  15. 登陆+注册(vue+elementUI)
  16. CSGO地图人物模型配置
  17. 硬盘安装windows系统
  18. canvas画笔自定义笔触
  19. 微软携手联想来酷试水渠道共享,打造创新销售通路
  20. basler相机的调试与配置以及多相机同时运行(完整版)

热门文章

  1. python3-泊松分布
  2. 知识点041-Samba 的安装
  3. 误删除的文件夹还能恢复吗?
  4. 开源加持 NFV借势OPNFV实现进阶之路
  5. 跨站访问如何保证session的正常使用
  6. Excel—SUMPRODUCT用法指南
  7. HTML开发中的一个问题
  8. 对付感冒的十二种偏方
  9. vi命令,印在杯子上,还是印在脑子里。
  10. 基于MATLAB和Python的频谱分析