channels 是 goroutines之间通信的工具, 可以理解为管道, 虽然go也提供共享变量的方式, 但是更加推荐使用channel
func TestChan(t *testing.T) { c := make(chan int) go func() { c <- 48 }() fmt.Println(<- c) // 保持持续运行 holdRun() } func holdRun() { time.Sleep(1 * time.Hour) }
c := make(chan int) 声明一个 传输整形 的unbuffer chan,(接收消息和发送消息者将会阻塞,直到channel ”可用“)
<- 操作符用来接受和发送消息 chan <- 48 发送“48“ 进入管道, <-chan 接收消息
如果: c: = make(chan int, 10) 声明一个 传输整形 的buffer chan, 容量为10, 接收消息将可以立即返回除非channel里面没有消息, 发送者返回除非容量满
func TestDeadLock(t *testing.T) { c := make(chan int) c <- 42 val := <-c fmt.Println(val) } func TestDeadLock1(t *testing.T) { c := make(chan int) //c := make(chan int, 0) go func() { c <- 48 }() val := <-c fmt.Println(val) } func TestDeadLock2(t *testing.T) { c := make(chan int, 1) c <- 42 val := <-c fmt.Println(val) }对于方法, TestDeadLock 将:fatal error: all goroutines are asleep - deadlock! 因为c <- 42 将会一直阻塞,直到出现消费者, 无容量的chan是同步, 正确的写法是 TestDeadLock1 这样不会死锁, 或者 TestDeadLock2 也不会死锁
func TestChan(t *testing.T) { c := make(chan int, 10) go func() { c <- 48 c <- 96 time.Sleep(2 * time.Second) c <- 200 }() time.Sleep(1 * time.Second) for v := range c { fmt.Println(v) } // 保持持续运行 holdRun() }chan 可以配合 range 使用, 相当于每次foreach 每次去取一次
func TestDChan(t *testing.T) { c := make(chan int) go f1(c) holdRun() } func f1(c chan <- int) { c <- 0 <- c }f1的参数类型是 chan <- int 表明 这个chan单向的, 只能用来接收。 f1函数编译错误:invalid operation: <-c (receive from send-only type chan<- int)
相对应的发送的chan : c <-chan string
select 关键字可以和 chan使用, 类似与switch
func TestSelect(t *testing.T) { c1 := make(chan int) c2 := make(chan int, 10) c3 := make(chan int, 20) go func(c1, c2, c3 chan<- int) { for { time.Sleep(1 * time.Second) c1 <- 1 time.Sleep(1 * time.Second) c1 <- 1 time.Sleep(1 * time.Second) c1 <- 2 time.Sleep(1 * time.Second) c1 <- 3 } }(c1, c2, c3) for { select { case int1 := <-c1: fmt.Println("c1 value :", int1) case int2 := <-c2: fmt.Println("c2 value :", int2) case int3 := <-c3: fmt.Println("c3 vaule :", int3) case <-time.After(2 * time.Second): fmt.Println("timeount") } } }select 将阻塞直到有一个chan ready或者 超时,即 time.After
select { case int1 := <-c1: fmt.Println("c1 value :", int1) case int2 := <-c2: fmt.Println("c2 value :", int2) case int3 := <-c3: fmt.Println("c3 vaule :", int3) default: fmt.Println("nothing ready") }
select 将不会阻塞, 直接执行 default
附 :
time.Afer 实现:
func After(d Duration) <-chan Time { return NewTimer(d).C }
func NewTimer(d Duration) *Timer { c := make(chan Time, 1) t := &Timer{ C: c, r: runtimeTimer{ when: when(d), f: sendTime, arg: c, }, } startTimer(&t.r) return t }
NewTimer 返回一个 timer (timer是一个一次性时间,d 时间后 发送当前时间给 C) , 由于C在此之前会一直阻塞。从而达到超时的效果
有疑问加站长微信联系(非本文作者)