Go语言程序设计-第8章--goroutine 和通道

Go语言程序设计-第8章--goroutine 和通道

8.1 goroutine

当程序启动时,只有一个 goroutine 来调用 main 函数,称为主 goroutine. 新的 goroutine 需要通过 go 语句进行创建。在普通的函数或者方法调用前边加上 go 关键字。

go 复制代码
f() // 调用f
go f() // 新建一个调用 f() 的 goroutine,不用等待。

8.4 通道

goroutine 是 Go 程序的并发的执行体,通道就是他们之间的连接。通道是可以让一个 goroutine 发送特定值到另一个 goroutine 的通信机制。每个通道是一个具体类型的导管,叫作通道的元素类型。一个有 int 类型元素的通道写为 chan int.

使用内置的 make 函数来创建一个通道:

go 复制代码
ch := make(chan int)

通道的零值是 nil。同种类型的通道可以使用 == 符号进行比较。

通道主要有两个主要操作:发送和接收,两者统称为通信。

go 复制代码
ch <- x // 发送语句
x = <- ch //赋值语句中的接收表达式

通道支持 close, 用法 close(ch)。如果 close 之后,再执行发送操作,会导致宕机。如果在一个已经关闭的通道上执行读操作,将获取所有已经发送的值,直到通道为空;这时任何接收操作会立即完成,同时获取到一个通道元素类型对应的零值。

创建通道是可以接受第二个可选参数,一个表示通道容量的整数。如

go 复制代码
ch = make(chan int) // 无缓冲通道
ch = make(chan int, 0) // 无缓冲通道
ch = make(chan int, 3) // 容量为 3 的缓冲通道

8.4.1 无缓冲通道

无缓冲通道上的发送操作将会阻塞,直到另一个 goroutine 的对应的通道上执行接收操作,这时值传送完成,两个 goroutine 都可以继续执行。相反,如果接收操作先执行,接收方 goroutine 将阻塞,直到另一个 goroutine 在同一个通道上发送一个值。

8.4.2 管道

通道可以用来连接 goroutine,这样一个的输出是另一个的输入,这个叫作管道(pipeline)。

结束时,关闭每个通道不是必须的。通道可以通过垃圾回收器根据它是否可以访问来决定是否回收它。试图关闭一个已经关闭的通道会导致宕机。

8.4.3 单向通道类型

go 复制代码
package main

import "fmt"

//!+
func counter(out chan<- int) {
	for x := 0; x < 100; x++ {
		out <- x
	}
	close(out)
}

func squarer(out chan<- int, in <-chan int) {
	for v := range in {
		out <- v * v
	}
	close(out)
}

func printer(in <-chan int) {
	for v := range in {
		fmt.Println(v)
	}
}

func main() {
	naturals := make(chan int)
	squares := make(chan int)

	go counter(naturals)
	go squarer(squares, naturals)
	printer(squares)
}

8.4.4 缓冲通道

如果无缓冲通道,发送的 goroutine 发送数据到通道时,如果没有 goroutine 来接收,这个情况叫作 goroutine 泄露。不像回收变量,泄露的 goroutine 不会自动回收。

8.7 使用 select 多路复用

go 复制代码
select {
	case <- ch1
		// 
	case x <- ch2
	// 
	case ch3 <- y :
    //
    default
}

select 和 switch 语句一样,它有一系列的情况和一个可选的默认分支。每一个情况指定一次通信和关联的一段代码。

select 一直等待,直到一次通信来告知有一些情况可以执行。如果多个情况同时满足,select 随机选择一个,这样保证每个通道有相同的机会被选中。

非阻塞通道

下面的select 执行时会立即返回,不论通道里有没有数据。

go 复制代码
select {
case <- abort:
	fmt.Printf("Launch aborted !\n")
	return
default:
 // 不执行任何操作  
}

8.9 取消

我们需要一个可靠的机制,在一个通道上广播一个事件,这样很多 goroutine 可以认为它已经发生了,然后可以看到他已经发生。

当一个通道已经关闭并且读完所有的发送的值后,接下来的读操作立即返回。

go 复制代码
var done = make(chan struct{})

func cancelled() bool {
	select {
		case <- done:
			return true
		default:
			return false
	}
}

go func() {
	os.Stdin.Read(make([]byte, 1))
	close(done)
}()
相关推荐
Buleall2 分钟前
期末考学C
java·开发语言
重生之绝世牛码4 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行10 分钟前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试
MARIN_shen16 分钟前
Marin说PCB之POC电路layout设计仿真案例---06
网络·单片机·嵌入式硬件·硬件工程·pcb工艺
Algorithm157620 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
新手小袁_J35 分钟前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
呆呆小雅36 分钟前
C#关键字volatile
java·redis·c#
Monly2136 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
Ttang2338 分钟前
Tomcat原理(6)——tomcat完整实现
java·tomcat
钱多多_qdd1 小时前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring