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)
}()
相关推荐
shuair1 小时前
idea 2023.3.7常用插件
java·ide·intellij-idea
小安同学iter2 小时前
使用Maven将Web应用打包并部署到Tomcat服务器运行
java·tomcat·maven
Yvonne9782 小时前
创建三个节点
java·大数据
饮长安千年月2 小时前
Linksys WRT54G路由器溢出漏洞分析–运行环境修复
网络·物联网·学习·安全·机器学习
不会飞的小龙人3 小时前
Kafka消息服务之Java工具类
java·kafka·消息队列·mq
是小崔啊3 小时前
java网络编程02 - HTTP、HTTPS详解
java·网络·http
brevity_souls4 小时前
Spring Boot 内置工具类
java·spring boot
小钊(求职中)4 小时前
Java开发实习面试笔试题(含答案)
java·开发语言·spring boot·spring·面试·tomcat·maven
shix .4 小时前
什么是tomcat
java·tomcat
java技术小馆4 小时前
Deepseek整合SpringAI
java·spring cloud