【重学Golang】10-协程和Channel

168 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

进程、线程、协程

进程和线程

  • 进程:程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位
  • 线程:是进程的一个执行实体,是CPU调度和分派的基本单位,比进程小能独立运行的基本单位
  • 一个进程可以创建和撤销多个线程,同一个进程中的多个线程可以并发执行

进程和协程

  • 协程:由用户的程序调度的,系统不知道协程的存在。独立的栈空间,共享堆空间。

    • 内存消耗远比 JAVA、C的线程少
    • 切换协程是开销远比线程小
    • 仅3个寄存器修改
  • 线程:一个线程上可以跑多个协程,协程是轻量级的线程。

    • 内存消耗大概 8M
    • 切换线程涉及模式切换(用户态切换内核态)、16个寄存器刷新

协程是 go语言中提出的概念,本质上就是 goroutine。所以,Go语言上支持协程的调度,封装了对 goroutine 的调度和处理。如长时间执行或系统调用时,主动将当前 goroutine 的CPU 转让出去。

协程应用

在一个函数调用前加上go关键字,这次调用就会在一个新的goroutine中并发执行。当被调用的函数返回时,这个goroutine也自动结束。

func hello() {
    fmt.Println("Hello Goroutine!")
}
func main() {
    go hello()
    fmt.Println("main goroutine done!")
}

所以,执行以上代码时,你会发现只打印 main goroutine done!.并没有打印Hello Goroutine! 因为main函数执行完之后goroutine也结束了。启动的hello 时异步并行的,main函数结束goroutine就会一同结束。所以可能hello 函数还没执行完,整个main 就结束了导致就没有输出hello函数的结果。

并发模型的通信 Channel

启动多个goroutine 后,每个goroutine 之间如何通信?

共享内存方式:使用go的 消息机制 channel 。channel 是 Go 语言在语言级别提供的 goroutine 间的通信方式。

channel的声明。使用关键字 chan。一个 channel 只能传递一种类型的值,这个类型需要在声明 channel 时指定。

var chanName chan ElementType
​
var ch1 chan int
var ch2 chan bool

声明一个 channel 需要使用 make 函数初始化之后才可以使用。如上如过声明后,零值是空值 nil。

ch := make(chan int)
​
// 写入
ch <- value
// 读出
value := <- ch
// 关闭 
close(ch)

对一个 channel 写入数据就需要读出,如果一直都不读出将导致堵塞。关闭 channel 时,需要通知接收方goroutine所有的数据都发送完毕的时候才需要关闭通道。

参考资料: