认识Go中的Goroutine和Channel

76 阅读2分钟

Go 语言的并发编程主要依赖于 goroutine 和 channel。下面我们将分别介绍 goroutine 和 channel 的基本概念和用法。

Goroutine

Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理。与操作系统线程相比,goroutine 具有更小的栈空间、更低的创建和销毁开销,以及更高的调度效率。在 Go 程序中,可以同时运行成千上万个 goroutine。

创建 goroutine 的方法非常简单,只需在函数调用前加上关键字 go。下面是一个简单的示例:

package main

import (
	"fmt"
	"time"
)

func printNumbers() {
	for i := 1; i <= 5; i++ {
		fmt.Println(i)
		time.Sleep(1 * time.Second)
	}
}

func printLetters() {
	for i := 'a'; i <= 'e'; i++ {
		fmt.Printf("%c\n", i)
		time.Sleep(1 * time.Second)
	}
}

func main() {
	go printNumbers()
	go printLetters()

	// 等待 goroutine 执行完成
	time.Sleep(6 * time.Second)
}

在这个示例中,我们创建了两个 goroutine,分别执行 printNumbers 和 printLetters 函数。这两个函数会并发地打印数字和字母,每次打印之间暂停 1 秒。最后,在 main 函数中,我们等待 6 秒以确保所有 goroutine 执行完成。

Channel

Channel 是 Go 语言中用于在不同 goroutine 之间传递数据的同步原语。通过使用 channel,我们可以在多个 goroutine 之间安全地共享数据,而无需显式地使用锁或其他同步机制。

创建 channel 的方法是使用内置函数 make,并指定 channel 的类型和可选的容量。下面是一个简单的示例:

package main

import "fmt"

func producer(ch chan int) {
	for i := 1; i <= 5; i++ {
		ch <- i
	}
	close(ch)
}

func consumer(ch chan int) {
	for n := range ch {
		fmt.Println(n)
	}
}

func main() {
	ch := make(chan int)

	go producer(ch)
	go consumer(ch)

	// 等待 goroutine 执行完成
	time.Sleep(1 * time.Second)
}

在这个示例中,我们创建了一个无缓冲的整数 channel chproducer 函数向 channel 中发送数字 1 到 5,然后关闭 channel。consumer 函数从 channel 中接收并打印数字,直到 channel 被关闭。最后,在 main 函数中,我们等待 1 秒以确保所有 goroutine 执行完成。

需要注意的是,无缓冲的 channel 在发送和接收操作上是阻塞的,即发送操作会阻塞,直到有其他 goroutine 执行接收操作;接收操作会阻塞,直到有其他 goroutine 执行发送操作。这样,无缓冲的 channel 可以用于实现 goroutine 之间的同步。

此外,Go 语言还支持带缓冲的 channel,通过指定 channel 的容量可以实现非阻塞的发送和接收操作。带缓冲的 channel 在发送操作时,只有在缓冲区满时才会阻塞;在接收操作时,只有在缓冲区空时才会阻塞。这样,带缓冲的 channel 可以用于实现 goroutine 之间的异步通信。

总之,Go 语言的并发编程主要依赖于 goroutine 和 channel。通过 goroutine,我们可以轻松地创建并发任务;通过 channel,我们可以在多个 goroutine 之间安全地共享数据。Go 语言的并发编程模型简单易用,可以帮助开发者更轻