channel
无缓冲channel
func main() {
ch := make(chan int) //无缓冲的channel
go func () {
time.Sleep(time.Second)
fmt.Println("finish?")
<-ch //阻塞,直到channel有值
}()
ch <- 1 //阻塞,直到channel内值传出
fmt.Println("yes")
}
// 输出结果:
// finish?
// yes
带缓冲channel
func mirroredQuery() string {
responses := make(chan string, 3) //可通过cap()得到容量,此时是3;len()得到有效元素的个数,此时是0
go func() { responses <- request("asia.gopl.io") }()
go func() { responses <- request("europe.gopl.io") }()
go func() { responses <- request("americas.gopl.io") }()
return <-responses // 返回最先得到的response,后面不使用该channel时,会自动垃圾回收
} //如果这里使用的是无缓冲channel,其中两个协程会一直阻塞在那里,不会进行垃圾回收
func request(hostname string) (response string) { /* ... */ }
channel的close()
func main() {
naturals := make(chan int)
squares := make(chan int)
go func() {
for x := 0; x < 100; x++ {
naturals <- x
}
close(naturals)
}()
go func() {
for x := range naturals { //当channel被关闭并且没有值可接收时跳出循环
squares <- x * x
}
close(squares)
}()
for x := range squares {
fmt.Println(x)
}
m,ok := <-squares //当channel被关闭后,再传入值会发起panic,而且传出操作不再阻塞
fmt.Println(m,ok) //打印结果:0 false。第二个返回值,ture表示成功从channels接收到值,false表示channels已经被关闭并且里面没有值可接收
}
//不管一个channel是否被关闭,当它没有被引用时将会被Go语言的垃圾自动回收器回收。
单方向channel
func counter(out chan<- int) {
for x := 0; x < 100; x++ {
out <- x
}
close(out) //可以关闭chan<-类型,关闭<-chan类型会报错
}
func squarer(out chan<- int, in <-chan int) {
for v := range in {
out <- v * v
}
close(out)
}
func printer(in <-chan int) {
for v := range in {
fmt.Println(v)
}
}
func main() {
naturals := make(chan int)
squares := make(chan int)
go counter(naturals) //传入双向chan,可自动转换为单向chan。但不可反过来
go squarer(squares, naturals)
printer(squares)
}
select
select { //选择一个优先完成通讯的分支执行,如果没有default分支,会阻塞直到其中一个有通讯产生;如果有多个分支都满足,随机选择一个执行
case <-chan1:
//...
case <-chan2:
//...
case <-chan3:
//...
default:
//...
}
sync
func main(){
var l sync.Mutex
var w sync.WaitGroup
var counter int
w.Add(5000) //或者在每个go协程之前w.Add(1)
for i := 0; i < 5000; i++{
//w.Add(1)
go func(){
l.Lock() //加锁保护共享变量,必须在本协程内解锁,其他协程才能操作该变量
counter ++
l.Unlock()
w.Done()
}()
}
w.Wait() //阻塞,直到执行了5000次w.Done()
fmt.Println(counter)
}
//输出结果:5000
//当获得锁的大部分goroutine都是读操作,可以使用sync.RWMutex及其方法Rlock()、RUnlock(),其允许多个只读操作并行执行,但写操作会完全互斥。这种锁叫作“多读单写”锁(multiple readers, single writer lock)
//sync.Once,其内部包含一个mux和bool,第一次调用Do时,执行传入的函数并将bool置位true,此后再调用Do时发现bool为true就不再执行传入的函数
//往往用在需要一次性的初始化时
var once sync.Once
for i := 0; i < 1000; i++{
go func (){
once.Do(init)
do something...
}
}