Channel

目录

channel

channel 是Go语言中用于Goroutine之间通信的工具,它相当于一个管道,有往channel里发送数据的发送方,也有从channel里读取数据的 消费方。发送和消费channel中的数据都是使用 <- 这个符号,但是它的位置放在左边还是右边就代表着不同的意思,箭头指向谁,数据 就往那个方向流动:

  • v := <-myChan 就说明数据是从 myChan 里读取出来,流动到 v 这个变量里
  • myChan <- v 则说明数据是从v流动到 myChan

初始化channel要使用 make 关键字,例如:

package main

import (
	"fmt"
	"time"
)

func main() {
	x := make(chan int)

	go func() {
		fmt.Println(<-x)
	}()

	time.Sleep(time.Second * time.Duration(1))
	x <- 1
	time.Sleep(time.Second * time.Duration(1))
}

channel 有三种形式,双向、只读、只写:

package main

import (
	"fmt"
)

func main() {
	x := make(chan int)
	y := make(chan<- int)
	z := make(<-chan int)

	fmt.Printf("%T, %T, %T\n", x, y, z)
}

注意上面的例子里,make(chan<- int) 创建出来的channel只能写入数据,make(<-chan int) 创建出来的channel只能读取数据,他们都是 单向channel。

select

读取channel中的数据是会被阻塞住的,那么我们要怎么才能实现如果channel中没有数据就继续执行呢?答案是使用 select

package main

import (
	"fmt"
	"time"
)

func main() {
	x := make(chan int)
	go func() {
		// 这里要睡10s,但是主Goroutine没有睡10s,因此这里是执行不到的,从而主Goroutine会在select里跳到default里
		time.Sleep(time.Second * time.Duration(10))
		x <- 1
	}()

	select {
	case i := <-x:
		fmt.Printf("从x中接收到%d\n", i)
	default:
		fmt.Printf("其他分支都阻塞了,所以轮到我执行\n")
	}

	fmt.Println("退出")
}

select 语句在形式上与 switch...case... 是一样的,不过 select 用于从多个阻塞的 goroutine 里监听,哪个分支 最先唤醒,就执行那个分支,当然,也有 default 分支,用于当所有 case 都阻塞时,跳过这个 select



更多文章
  • 利用Github的WebHook完成自动部署
  • 使用Tornado和rst来写博客
  • Haskell do notation
  • foldl 和 foldr 的变换
  • Haskell TypeClass 笔记
  • 重新捡起你那吃灰的树莓派
  • Tornado 源码阅读
  • JavaScript权威指南笔记
  • Python零碎知识汇总
  • C语言的位操作
  • 分治
  • 关于python的decorator和descriptor
  • 程序设计实践笔记
  • Thinking Recursively
  • Block I/O