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



更多文章
  • ssh时自动运行tmux
  • ufw简明教程
  • zerotier简明教程
  • 提取kindle笔记
  • 一个Golang gRPC握手错误的坑
  • Golang(Go语言)爬虫框架colly简明教程及源码阅读与分析
  • 选择合适的技术栈
  • Golang的template(模板引擎)简明教程
  • 毕业三年,一路走来
  • 代码的坏味道
  • 消息分帧(字符串设计或协议设计)的两种形式
  • C, Go, Python的错误处理和异常机制杂谈
  • 好的命名是最好的文档
  • 读《系统之美:决策者的系统思考》
  • Linux高分屏支持