goroutine 是一个普通的函数,go作为开头
1 package main 2 3 import ( 4 "fmt" 5 "time" 6 ) 7 8 func ready(w string, sec int) { 9 time.Sleep(time.Duration(sec) * time.Second) 10 fmt.Println(w, "is ready!") 11 } 12 13 func main() { 14 go ready("Tea", 2) 15 go ready("Coffee", 1) 16 fmt.Println("I'm waiting") 17 time.Sleep(5 * time.Second) //移除这行程序会立即停止,所以需要用到管道channels 18 }
结果:
I'm waiting //立刻出现
Coffee is ready! //1秒出现
Tea is ready! //2秒出现
这一机制通过channels的形式使用,与sehll中的双向管道做类比:可以通过它发送或者接受值。
必须使用make创建channel
ci := make(chan int) //用于发送和接受整数 cs := make(chan string) cf := make(chan interface{}) ci <- 1 //发送整数1到channel ci <-ci //从channel ci接收整数 i := <-ci //从channel ci接收整数,并保存到i中
1 package main 2 3 import ( 4 "fmt" 5 "time" 6 ) 7 //定义c作为int型的channel 8 var c chan int 9 10 func ready(w string, sec int) { 11 time.Sleep(time.Duration(sec) * time.Second) 12 fmt.Println(w, "is ready!") 13 c <- sec 14 } 15 16 func main() { 17 //初始化c 18 c = make(chan int) 19 go ready("Tea", 2) 20 go ready("Coffee", 1) 21 fmt.Println("I'm waiting") 22 //<-c 等待直到从channel上接收一个值,收到的值被丢弃 23 fmt.Println(<-c) 24 //<-c 两个goroutines,接收两个值 25 fmt.Println(<-c) 26 }
結果:
I'm waiting
Coffee is ready!
1
Tea is ready!
2
select
不得不從channel中读取两次23和25行,如果不知道启动了多少个go怎么办
通过select可以监听channel上输入的数据
1 package main 2 3 import ( 4 "fmt" 5 "time" 6 ) 7 8 //定义c作为int型的channel 9 var c chan int 10 11 func ready(w string, sec int) { 12 time.Sleep(time.Duration(sec) * time.Second) 13 fmt.Println(w, "is ready!") 14 c <- sec 15 } 16 17 func main() { 18 //初始化c 19 c = make(chan int) 20 go ready("Tea", 2) 21 go ready("Coffee", 1) 22 fmt.Println("I'm waiting") 23 i := 0 24 L: 25 for { 26 select { 27 case <-c: 28 i++ 29 if i > 1 { 30 break L 31 } 32 } 33 } 34 fmt.Println(i) 35 }
結果:
I'm waiting
Coffee is ready!
Tea is ready!
2
虽然goroutine是并发执行的,但是它们并不是并行运行,同一时刻只会有一个go执行,利用runtime.GOMAXPROCE(n)可以
设置go并行执行的数量
创建chan
ch := make(chan type, value)
value == 0 无缓冲,例如: val := <-ch 它会被阻塞,直到有数据接收,任何发送(ch <-5 )将会被阻塞,直到数据被读出
value > 0 缓冲value的元素
关闭chan
x, ok = <-ch 当ok为true时表示chan没被关闭,可以读取数据