Go协程安全
多路复用 Go语言中提供了一个关键字select,通过select可以监听channel上的数据流动。select的用法与switch语法类似,由select开始一个新的选择块,每个选择条件由case语句来描述。只不过,select的case有比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作。 select 语法如下: go 1 2 3 4 5 6 7 8 select { case <-chan1: // 如果chan1成功读到数据,则进行该case处理语句 case chan2 <- 1: // 如果成功向chan2写入数据,则进行该case处理语句 default: // 如果上面都没有成功,则进入default处理流程 } 在一个select语句中,会按顺序从头至尾评估每一个发送和接收的语句;如果其中的任意一语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用。如果没有任意一条语句可以执行(即所有的通道都被阻塞),那么有两种可能的情况:⑴ 如果给出了default语句,那么就会执行default语句,同时程序的执行会从select语句后的语句中恢复。⑵ 如果没有default语句,那么select语句将被阻塞,直到至少有一个channel可以进行下去。 在一般的业务场景下,select不会用default,当监听的流中再没有数据,IO操作就 会阻塞现象,如果使用了default,此时可以出让CPU时间片。如果使用了default 就形成了非阻塞状态,形成了忙轮训,会占用CPU、系统资源。 阻塞与非阻塞使用场景 阻塞: 如:在监听超时退出时,如果100秒内无操作,择退出,此时添加了default会形成忙轮训,超时监听变成了无效。 非阻塞: 如,在一个只有一个业务逻辑处理时,主进程控制进程的退出。此时可以使用default。 定时器 Go语言中定时器的使用有三个方法 time.Sleep() time.NewTimer() 返回一个时间的管道, time.C 读取管道的内容 time.After(5 * time.Second) 封装了time.NewTimer(),反回了一个 time.C的管道 示例 go 1 2 3 select { case <-time.After(time.Second * 10): } 锁和条件变量 Go语言中为了解决协程间同步问题,提供了标准库代码,包sync和sync/atomic中。 互斥锁 互斥锁是传统并发编程对共享资源进行访问控制的主要手段,它由标准库sync中的Mutex结构体类型表示。sync.Mutex类型只有两个公开的指针方法,Lock和Unlock。Lock锁定当前的共享资源,Unlock进行解锁。 go 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 package main import ( "fmt" "runtime" "sync" "time" ) var mutex sync....