> 协程是Go语言的关键特性,主要用于并发编程,协程是一种轻量级的线程,因为协程开销比较小,所以创建上万的协程也不是什么难事
[TOC]
## 创建并运行协程
> 通过go关键词创建一个协程
```
go dotest()
```
> 例子
> go携程特性:当主携程退出后,子携程随之退出
```
package main
import (
"fmt"
"strconv"
"time"
)
// 定义一个函数,循环打印5次字符串
func say(name string) {
for i := 0; i < 5; i++ {
// 当前协程休眠1秒
time.Sleep(1000 * time.Millisecond)
fmt.Println(name + strconv.FormatInt(int64(i), 10))
}
}
// 程序启动的时候,首先创建一个主协程,运行main函数
func main() {
// 创建一个协程,运行say函数,传入参数"wk"
go say("wk")
// 在主协程中运行say函数,传入参数"jiaojiao"
go say("jiaojiao")
// 以下代码,设置无线循环,可组织主携程退出
/*for {
;
}*/
}
```
> 以上例子,wk和jiaojiao交叉输出,但是有可能say("jiaojiao")函数先执行完成,主程就会退出,导致say("wk")函数的携程没有执行完毕就终止了。
> 解决这种问题,就需要用到`channel通信`,如下
~~~
package main
import "fmt"
func doubleNum(num int, c chan int) {
c <- num * 2
}
func main() {
// 定义一个无缓冲区的channel,用来接收协程计算结果
channel := make(chan int)
// 创建第1协程
go doubleNum(3, channel)
// 创建第2个协程
go doubleNum(2, channel)
// 使用channel读取,会进行阻塞,直到有数据后,才会往下执行
x := <-channel
y := <-channel
// 打印计算结果,主程退出
fmt.Println(x, y, x+y)
}
~~~
## 协程通信
> 协程之间通信主要有两种方式
> * [共享全局变量](https://www.tizi365.com/archives/457.html):因为协程本身是在同一个进程中运行,所以可以共享变量,但是为了解决并发问题,保证数据原子性,需要加锁处理。
> * channel:管道通信,避免复杂的加锁操作(下篇将进行介绍)
- 基础知识
- 开发环境
- 包名规则
- 包初始化 (init)
- 基础数据类型
- 基础类型转换
- 格式化输出
- go指针
- 流程控制语句
- 函数定义
- 匿名函数
- 数组和切片
- map集合
- 结构体
- Interface接口
- 日期处理
- 数学计算
- 正则表达式
- 协程 (并发处理)
- channel
- waitgroup
- mutex (锁机制)
- websocket
- protobuf
- Redis
- 错误处理
- 打包程序
- NSQ消息队列
- 单元测试
- beego
- 安装入门
- Gin
- 快速入门
- 路由与控制器
- 处理请求参数
- 表单验证
- 处理响应结果
- 渲染HTML模版
- 访问静态文件
- Gin中间件
- Cookie处理
- Session处理
- Gin上传文件
- swagger
- pprof性能测试
- GORM
- 入门教程
- 模型定义
- 数据库连接
- 插入数据
- 查询数据
- 更新数据
- 删除数据
- 事务处理
- 关联查询
- 属于 (BELONG TO)
- 一对一 (Has One)
- 一对多 (Has Many)
- 多对多 (Many to Many)
- 预加载 (Preloading)
- 错误处理
- 第三方常用插件
- viper 读取配置文件
- zap 高性能日志
- Nginx代理配置
- Goland 快捷键