Go有个简单的线程模型,叫做协程。为这个协程配套的简易版“数据同步”叫管道或者信道
在go tour上有两个很有特色的例子:
https://tour.go-zh.org/concurrency/2
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将和送入 c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从 c 中接收
fmt.Println(x, y, x+y)
}
这个例子中c信道被两个协程使用,但是对于x,y的赋值却不互相影响。深入的说,就是第一个二分之一切片协程优先把c信道填满了sum,然后另外一个处理后二分之一切片的协程就会自动等待c信道空间,而阻塞在c <- sum行。一直到x<-c,c信道被读出
第二个例子
https://tour.go-zh.org/concurrency/5
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
这个例子中叫死循环fibonacci可以通过select等待多个管道(c和quit)的动作。case c<-x当c信道需要填入的时候,把x填入给他,x的值可以通过case下的程序给出。case <-quit当quit信道有东西要输出的时候,当然也可以写成case q:=<-quit:然后在下面打印quit信道里面的值。
小结:
1.使用go+func就可以简单的实现异步线程
2.当需要在数据层面上做同步的时候,可以使用信道make chan
3.select可以帮助你识别信道的动作,当然这可能和传统思维是相反的,但适应一下就好了