php defer,PHP 协程:Go + Chan + Defer
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相关推荐
- go 怎么等待所有的协程完成_Go 编程:如何实现协程调度的精准控制
说起 Go 协程的调度,如果你了解 Go 调度器以及其实现的 G/P/M 模型,当然有助于应用的开发.但是在应用层面上,这些底层的调度原理并不会帮你太多,实现 Go 协程的精准调度得完全靠自己. 问题 ...
- go 怎么等待所有的协程完成_Go语言入门必知教程-协程
Golang中的并发性是指函数独立运行的能力.Goroutines就是能够并发运行的函数,也叫协程,它们是Golang提供作为并发处理操作的方法. 使用go语句创建协程goroutines 要将函数作 ...
- mysql 连接查询_Swoole 实战:MySQL 查询器的实现(协程连接池)
Swoole 实战:MySQL 查询器的实现(协程连接池) 需求分析 本篇我们将通过 Swoole 实现一个自带连接池的 MySQL 查询器: 1. 支持通过链式调用构造并执行 SQL 语句: 2. ...
- Golang - 协程池 ants.NewPoolWithFunc使用介绍
前言 ants是一个高性能的协程池,实现了对大规模goroutine的调度管理.goroutine复用,允许使用者在开发并发程序的时候限制协程数量,复用资源,达到更高效执行任务的效果. 提示:以下是本 ...
- Go 学习笔记(25)— 并发(04)[有缓冲/无缓冲通道、WaitGroup 协程同步、select 多路监听通道、close 关闭通道、channel 传参或作为结构体成员]
1. 无缓冲的通道 无缓冲的通道(unbuffered channel)是指在接收前没有能力保存任何值的通道. 这种类型的通道要求发送 goroutine 和接收 goroutine 同时准备好,才能 ...
- golang 协程同步 简介
目录 协程概念简要理解 为什么要做同步 协程的几种同步方法 Mutex channel WaitGroup 协程概念简要理解 协程类似线程,是一种更为轻量级的调度单位,但协程还是不同于线程的,线程是系 ...
- golang context 父子任务同步取消信号 协程调度 简介
目录 前言 为什么需要context context是什么 context的使用 总结 前言 这篇文章将介绍Golang并发编程中常用到一种编程模式:context.本文将从为什么需要context出 ...
- golang goroutine 协程原理
一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...
- golang 数组 最后一个_面试必问:Golang高阶Golang协程实现原理
1 01 引言 实现并发编程有进程,线程,IO多路复用的方式.(并发和并行我们这里不区分,如果CPU是多核的,可能在多个核同时进行,我们叫并行,如果是单核,需要排队切换,我们叫并发). 1.1 进程和 ...
最新文章
- 如何在Matlab中获取函数参数的数目?
- dom解析和生成XML文件
- linux挂载wondiws目录,linux cifs自动挂载windows硬盘或文件夹
- JS调用C#后台函数
- redis 零散知识
- 看完就能独自把集群搭起来!Hadoop HDFS完全分布式环境搭建以及技术详解
- 为什么重写equals时必须重写hashCode方法?
- Linux 命令(11)—— col 命令
- isp串口下载 stm32_快速入门STM32单片机
- XAMPP mysql远程连接
- java解压zip异常_zip 文件解压缩问题解决 java.util.zip.ZipException:error in opening zip file | 学步园...
- MySQL可视化软件(Navicat)部署与使用
- 网易邮箱登录php,PHP模拟登陆163邮箱发邮件及获取通讯录列表的方法
- 【图论】	腾讯大战360
- 登陆+注册(vue+elementUI)
- CSGO地图人物模型配置
- 硬盘安装windows系统
- canvas画笔自定义笔触
- 微软携手联想来酷试水渠道共享,打造创新销售通路
- basler相机的调试与配置以及多相机同时运行(完整版)