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

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

8.1 goroutine

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

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

8.4 通道

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

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

ch := make(chan int)

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

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

ch <- x // 发送语句
x = <- ch //赋值语句中的接收表达式

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

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

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 单向通道类型

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 多路复用

select {
    
    
	case <- ch1
		// 
	case x <- ch2
	// 
	case ch3 <- y :
    //
    default
}

select 和 switch 语句一样,它有一系列的情况和一个可选的默认分支。每一个情况指定一次通信和关联的一段代码。
select 一直等待,直到一次通信来告知有一些情况可以执行。如果多个情况同时满足,select 随机选择一个,这样保证每个通道有相同的机会被选中。

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

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

8.9 取消

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

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

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)
}()

猜你喜欢

转载自blog.csdn.net/houzhizhen/article/details/135438074
今日推荐