Go 协程会复用(Multiplex)数量更少的 OS 线程。即使程序有数以千计的 Go 协程,也可能只有一个线程。如果该线程中的某一 Go 协程发生了阻塞(比如说等待用户输入),那么系统会再创建一个 OS 线程,并把其余 Go 协程都移动到这个新的 OS 线程。所有这一切都在运行时进行,作为程序员,我们没有直接面临这些复杂的细节,而是有一个简洁的 API 来处理并发。
Go 协程使用信道(Channel)来进行通信。信道用于防止多个协程访问共享内存时发生竞态条件(Race Condition)。信道可以看作是 Go 协程之间通信的管道。
1.4 信道
1.4.1 声明信道
var c chan int // 方式一,为nil,不能发送也不能接受数据
c := make(chan int) // 方式二,可用
func printHello(c chan bool) {
fmt.Println("hello world goroutine")
<- c // 读取信道的数据
}
func main() {
c := make(chan bool)
go printHello(c)
c <- true // main 协程阻塞
fmt.Println("main goroutine")
fatal error: all goroutines are asleep - deadlock!
1.4.4 关闭信道与 for loop
val, ok := <- channel
val 是接收的值,ok 标识信道是否关闭。为 true 的话,该信道还可以进行读写操作;为 false 则标识信道关闭,数据不能传输。
使用内置函数 close() 关闭信道。
使用 for range 读取信道,信道关闭,for range 自动退出。 使用 for range 一个信道,发送完毕之后必须 close() 信道,不然发生死锁。
func printNums(ch chan int) {
for i := 0; i < 4; i++ {
ch <- i
}
close(ch)
}
func main() {
ch := make(chan int)
go printNums(ch)
for v := range ch {
fmt.Println(v)
}
}
请发表评论