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



微信公众号
关注公众号,获得及时更新

更多文章
  • HTTP 路由的两种常见设计形式
  • Golang的short variable declaration
  • Greenlet和Stackless Python
  • 写一个简单的ORM
  • 从源码看Python的descriptor
  • Python字符串格式化
  • Gunicorn 简明教程
  • Raft 论文阅读笔记
  • 什么是 Golang Comparable Types
  • GFS 论文阅读
  • MapReduce 论文阅读
  • 一起来做贼:Goroutine原理和Work stealing
  • Go语言的defer, panic和recover
  • 再读 Python Language Reference
  • 再读vim help:vim小技巧