社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
Golang 一个重要的优点就是可以容易实现并发的架构,它通过提供goroutine和channel的语言机制,很简单、方便的实现了这个优点。
goroutine简单理解就是轻量版的线程, 协程就是一个不由OS内核抢占调度,而由程序管理在用户态自管理的协作式“线程”,不用线程,就减少了OS的线程数,其优点:
关于goroutine, 没有比较官方的文档, 我们从如下的文章翻译得到关于goroutine 调度器的说明:go-scheduler链接
Go的调度器内部有三个重要的结构:M,P,S:
用户空间线程和内核空间线程之间的映射关系有:N:1,1:1和M:N
goroutine的调度模型:
图中看,有2个物理线程M,每一个M都拥有一个context(P),每一个也都有一个正在运行的goroutine。P的数量可以通过GOMAXPROCS()来设置,它其实也就代表了真正的并发度,即有多少个goroutine可以同时运行。图中灰色的那些goroutine并没有运行,而是出于ready的就绪态,正在等待被调度。P维护着这个队列(称之为runqueue),Go语言里,启动一个goroutine很容易:go function 就行,所以每有一个go语句被执行,runqueue队列就在其末尾加入一个goroutine,在下一个调度点,就从runqueue中取出(如何决定取哪个goroutine?)一个goroutine执行。
在GO里面, 启动一个协程很简单, 只需要在函数前面加上关键字go, 通常启动一个协程, 需要配合for-loop, 保证该协程持续存在。
- 方式1:命名协程
package main
import(
"fmt"
"time"
)
func routeFunc() {
for {
fmt.Printf("run this test.")
time.Sleep(time.Minute)
}
}
func main() {
go routeFunc()
...
}
package main
import(
"fmt"
"time"
)
func main() {
go func() {
for {
fmt.Printf("run this test.")
time.Sleep(time.Minute)
}
}();
...
在并发体系里面,另外一个比较重要的机制就是channel,因为它可以实现goroutine之间的通信。我们知道,不同的goroutine是并行执行的,在很多场景下, 需要将执行的结构通知给main 协程,比较常见的办法就是在主协程和执行协程之间建一个channel。
channel 分为带缓存和不带缓存管道:
c1:=make(chan int) //无缓冲
c2:=make(chan int,1) //有缓冲
c1<-1
无缓冲: 不仅仅是向 c1 通道放 1,而是一直要等有别的携程 <-c1 接手了这个参数,那么c1<-1才会继续下去,要不然就一直阻塞着。
有缓冲: c2<-1 则不会阻塞,因为缓冲大小是1(其实是缓冲大小为0),只有当放第二个值的时候,第一个还没被人拿走,这时候才会阻塞。
用cahnnel 配合select 实现多路复用,select的一个case代表一个通信操作(在某个channel上进行发送或者接收)并且会包含一些语句组成的一个语句块。
package main
import (
"fmt"
"os"
)
func connectFunc(connChan chan int) {
int result GetNewConnect();
connChan <- result
}
func isAborted(abort chan int) {
os.Stdin.Read(make([]byte, 1))
abort <- -1
}
func main() {
abortChan := make(chan int)
connChan := make(chan int)
go isAbort(abortChan)
go connectFunc(connChan)
select {
case <- connChan:
fmt.Println("Got one new connection")
return
case <- abortChan:
fmt.Println("Launch aborted!")
return
}
}
在这个例子里, 首先创建2个int类型的channel, connChannel, abortChan, 然后启动2个协程, 并且将结果写入相应的channel。 select是类似switch/case 的使用方式, 每当协程有结果写入abortChan或者connChan, select就能够接收到, 并且进行相应的处理。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!