golang 深入理解学习 channel 和 goroutine

通道分为无缓冲通道和有缓冲通道,无缓冲通道上的发送操作将会阻塞,直到另一个 goroutine 在对应的通道上执行接受操作,这时值传送完成,两个 goroutine 都可以继续执行,使用无缓冲通道进行的通信导致发送和接受 goroutine 同步化,当一个值在无缓冲通道上传递时,接受值后发送方 goroutine 才会被唤醒.

关闭通道

  1. 在通道关闭后,任何后续发送操作将会导致应用崩溃.
  2. 当关闭的通道被读完后,所有后续的接收操作顺利畅通进行,只是获取到的是零值.
  3. 目前没有直接的方式判断通道关闭,不过网上有很多判断通道关闭而封装的函数,可以自己拿过来试一试
  4. 发送方结束时,关闭每一个通道不是必需的.只有通知接收方 goroutine 所有的数据都发送完毕的时候才需要关闭通道.通道也是可以通过垃圾回收器根据它是否可以访问来决定是否回收它,而不是根据它是否关闭.

简单关闭通道

版本一:使用无缓冲通道,阻塞等待协程执行结束.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import (
	"testing"
	"time"
)

func TestCloseChan(t *testing.T) {
	CloseChan(t)
}
func CloseChan(t *testing.T) {
	i := make(chan int)
	a := make(chan int)
	go func() {
		time.Sleep(time.Second * 2)
		t.Log("do first thing!")
		i<-0 //协程执行结束,发送消息告诉主进程
	}()

	t.Log("continue do something!")
	go func() {
		time.Sleep(time.Second *3)
		t.Log("do second thing!")
		a<-0 //协程执行结束,发送消息告诉主进程

	}()

	<-i //阻塞等待协程发送消息
	<-a
	t.Log("finish!")
}

版本二:使用无缓冲通道,阻塞等待协程执行结束,协程执行结果不重要,直接关闭通道,阻塞等待的主进程,接收到为 0 的消息.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29


import (
	"testing"
	"time"
)

func TestCloseChan(t *testing.T) {
	CloseChan(t)
}
func CloseChan(t *testing.T) {
	i := make(chan int)
	a := make(chan int)
	go func() {
		defer  close(i) //协程执行结束,直接关闭通道,无返回消息
		time.Sleep(time.Second * 2)
		t.Log("do first thing!")
	}()

	t.Log("continue do something!")
	go func() {
		defer  close(a) //协程执行结束,直接关闭通道,无返回消息
		time.Sleep(time.Second *3)
		t.Log("do second thing!")
	}()
	<-i //阻塞等待协程发送消息
  t.log(	<-a)
	t.Log("finish!")
}