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)
}()
相关推荐
卓越小Y3 分钟前
配置jellyfin docker 硬件加速
java·spring cloud·docker
白萝卜弟弟6 分钟前
【JAVA】正则表达式中的捕获组和非捕获组
java·正则表达式
袁庭新26 分钟前
LuaRocks如何安装数据库驱动?
java·数据库·redis·lua·luarocks·袁庭新
hummhumm35 分钟前
第 10 章 - Go语言字符串操作
java·后端·python·sql·算法·golang·database
nukix1 小时前
Mac Java 使用 tesseract 进行 ORC 识别
java·开发语言·macos·orc
月光光心慌慌。1 小时前
新日撸java三百行` 新手小白java学习记录 `Day1
java
蘑菇丁1 小时前
ranger-kms安装
java·ide·eclipse
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】内存可见性问题 & volatile
java·开发语言·java-ee
hope_wisdom1 小时前
C++网络编程之SSL/TLS加密通信
网络·c++·ssl·tls·加密通信
weixin_462428471 小时前
使用 Caffeine 缓存并在业务方法上通过注解实现每3到5秒更新缓存
java·缓存