Go语言异步编程:完整指南与示例

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么选择Go进行异步编程?



Go(Golang)从设计之初就为高效并发而生。与许多通过复杂回调或Promise实现异步的编程语言不同,Go提供了一种基于goroutine和channel的优雅模型。这种模型允许你编写看似同步、实际并行执行的异步代码,从而最大化多核处理器资源的利用率。



在本指南中,我们将涵盖Go异步编程的所有关键概念:从创建goroutine到使用channel和sync包中的原语实现复杂的同步模式。无论您是刚接触Go的初学者,还是希望系统化知识体系的经验丰富的开发者,本文都将为您带来实用价值。



1. Goroutine:轻量级线程



Goroutine是由Go运行时管理的轻量级执行线程。与操作系统线程不同,goroutine拥有微小的栈空间(初始仅数KB),且能动态伸缩。这使得数万个goroutine可以同时运行而不会显著消耗内存。



启动Goroutine

要将函数作为goroutine运行,只需在函数调用前添加关键字go:



package main

import ( "fmt" "time")

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

func main() { // 将函数作为goroutine运行 go printNumbers()

// 主goroutine继续执行 fmt.Println("主goroutine正在工作")

// 给子goroutine执行时间 time.Sleep(1 * time.Second) fmt.Println("程序运行结束")}


重要提示:当main()函数执行完毕时,程序会终止。如果主goroutine提前结束,所有子goroutine将被强制停止。因此示例中我们使用time.Sleep等待——实际开发中应使用channel或sync.WaitGroup进行同步。



Goroutine中的匿名函数

通常使用匿名函数创建goroutine:



go func() {    fmt.Println("正在goroutine中执行")}()


2. Channel:Goroutine间的通信机制



Channel是类型化的"管道",goroutine可通过它发送和接收值。这是Go中同步与数据交换的主要机制。Channel无需显式锁(互斥锁)即可提供安全的数据访问。



创建和使用Channel

使用make()函数创建channel。<-运算符用于发送和接收数据:



package main

import "fmt"

func sum(s []int, c chan int) { total := 0 for _, v := range s { total += v } c <- total // 将结果发送到channel}

func main() { s := []int{7, 2, 8, -9, 4, 0}

c := make(chan int) go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c)

x, y := <-c, <-c // 从channel接收数据

fmt.Println(x, y, x+y)}


本例中我们启动两个goroutine,分别计算切片一半元素的和。结果通过channel发送,主goroutine接收并打印总和。



带缓冲的Channel

默认情况下channel是无缓冲的——发送操作会阻塞直到接收方准备好接收值。带缓冲的Channel拥有指定大小的队列:



ch := make(chan int, 2) // 创建容量为2的缓冲channelch <- 1ch <- 2// ch <- 3 // 错误:死锁,缓冲区已满fmt.Println(<-ch) // 1fmt.Println(<-ch) // 2

博客

书籍推荐