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)
}()
相关推荐
努力写代码的熊大13 分钟前
c++异常和智能指针
java·开发语言·c++
山岚的运维笔记17 分钟前
SQL Server笔记 -- 第15章:INSERT INTO
java·数据库·笔记·sql·microsoft·sqlserver
Yvonne爱编码17 分钟前
JAVA数据结构 DAY5-LinkedList
java·开发语言·python
小王不爱笑1321 小时前
LangChain4J 整合多 AI 模型核心实现步骤
java·人工智能·spring boot
西凉的悲伤1 小时前
spring-boot-starter-validation使用注解进行参数校验
java·spring boot·参数校验·validation·注解校验参数
LucDelton1 小时前
Java 读取无限量文件读取的思路
java·运维·网络
夹锌饼干1 小时前
mysql死锁排查流程--(处理mysql阻塞问题)
java·mysql
小信丶1 小时前
@EnableTransactionManagement注解介绍、应用场景和示例代码
java·spring boot·后端
To Be Clean Coder1 小时前
【Spring源码】createBean如何寻找构造器(四)——类型转换与匹配权重
java·后端·spring
-孤存-2 小时前
SpringBoot核心注解与配置详解
java·spring boot·后端