5分钟了解 Go 语言中的 Goroutine 并发模型

一、前言

在 Go 中,有一个核心的概念就是 Goroutine,它是并发编程的基础。本文将探讨 Goroutine,以帮助你更好地理解并发编程在 Go 语言中的运作。

二、内容

2.1 什么是 Goroutine

"Go 的主要特色在于易于使用的并行设计,叫做 Goroutine。透过 Goroutine 能够让程序以异步的方式执行,而不需要担心一个函数导致程序中断,因此 Go 也非常地适合网络服务。" ------ 维基百科

Goroutine 是 Go 语言中的并发执行单元,与传统操作系统线程相比,它们非常轻量级。创建和销毁 Goroutine 的成本很低,这意味着你可以轻松地创建大量的 Goroutine,而不会造成显著的系统开销。这种轻量级特性使得 Go 能够高效地处理大规模并发任务,而不会导致系统负载急剧增加。

注意, Goroutine 是由 Go 语言的运行时系统进行管理和调度的。程序员不需要手动管理线程的创建和销毁,也不必担心线程之间的调度问题。这种自动管理的特性减轻了开发者的负担,让他们更专注于编写应用程序的逻辑。通过创建多个 Goroutine,我们可以同时执行多个任务,这对于处理网络请求、数据处理、并行计算等场景非常有用。Goroutine 的并发性让编写高性能、高并发的应用变得更加容易。

2.2 异步执行

Goroutine 的真正魅力在于其能够以异步的方式执行代码块,而无需担心一个函数的执行会阻塞整个程序。这意味着我们可以将耗时的操作,例如文件读写、网络请求或计算密集型任务,委托给 Goroutine 来处理,而主程序可以继续执行其他任务,而不会被阻塞。这种异步执行的方式使得 Go 语言非常适合构建高响应性的网络服务和并发应用程序。

2.3 Goroutine 的创建

在Go语言中,创建一个 Goroutine 非常简单,只需在函数调用前加上关键字 go 即可。

例如:

go 复制代码
go func() {
    // 这里是要在Goroutine中执行的代码
}()

上述代码片段就创建了一个新的 Goroutine ,它会异步执行匿名函数中的代码。这种方式极其高效,因为 Goroutine 的创建和销毁开销很小,且不需要像传统线程那样复杂的线程管理。

Go运行时包含一个高效的 Goroutine 调度器,它负责在不同的 Goroutine 之间进行任务切换,以实现并发执行。这个调度器在后台自动管理 Goroutine 的调度,使得开发者无需手动干预,减轻了多线程编程的复杂性。

Go运行时还提供了垃圾回收和内存管理,确保了 Goroutine 的资源有效利用和释放,避免了内存泄漏等问题。

当一个程序启动时,其主函数即在一个单独的goroutine中运行,我们叫它main goroutine

2.4 简单的例子

下面我们举一个简单的例子,用于展示如何使用 goroutine 来实现简单的并发。

需要注意的是,main goroutine 将计算菲波那契数列第 45 个元素值。这是一个计算密集型任务,因此需要耗费一点时间,我们在这个期间并发运行 animateProgressBar 函数,用于在终端显示一个进度条,以模拟一个正在运行的任务的进度。

go 复制代码
package main

import (
    "fmt"
    "time"
)

func main() {
    // 打印进度条
    go animateProgressBar(40 * time.Millisecond)

    // 计算菲波那契数列第 45 个元素值
    result := fib(45)

    fmt.Printf("\nresult = %d.\nMain goroutine exiting.", result)
}

// animateProgressBar 函数用于显示进度条
func animateProgressBar(delay time.Duration) {
    const width = 50
    progress := 0
    for {
        fmt.Printf("\r[%s] %d%%", progressBar(progress, width), progress)
        time.Sleep(delay)
        if progress == 100 {
            return
        }
        progress = (progress + 1) % 101
	}
}

// progressBar 生成进度条字符串
func progressBar(progress, width int) string {
    numBars := (progress * width) / 100
    bars := make([]byte, width)
    for i := 0; i < numBars; i++ {
        bars[i] = '='
    }
    return string(bars)
}

// fib 计算斐波那契数列的第 x 个元素
func fib(x int) int {
    if x < 2 {
        return x
    }
    return fib(x-1) + fib(x-2)
}

运行结果如下:

bash 复制代码
[==================================================] 100%
result = 1134903170.
Main goroutine exiting.

在这个示例中,两个独立的任务(显示进度条和计算斐波那契数列)是通过goroutine并发执行的。虽然它们在不同的函数中,但它们可以同时运行,而不会相互干扰。

具体细节如下:

  1. 在主函数执行计算斐波那契数列的同时,animateProgressBar 函数在后台不断更新并显示进度条,每隔40毫秒更新一次。
  2. 当计算斐波那契数列的任务完成时,主函数打印结果。此时,主函数返回,程序结束。
  3. 由于主函数返回,程序退出,所有 goroutine 也会被终止,包括用于显示进度条的 goroutine

三、总结

本文深入探讨了 Go 语言中的 Goroutine 并发模型,我们来小结一下:

  • Goroutine 是 Go 语言的并发执行单元,相对于传统线程更加轻量级,使得 Go 能够高效地处理大规模并发任务。
  • 异步执行是 Goroutine 的亮点,它允许耗时操作在不阻塞主程序的情况下执行,适用于构建高响应性的网络服务和并发应用。
  • Goroutine 的创建非常简单 ,只需在函数调用前添加关键字 go,而无需手动管理线程。Go 运行时系统会自动进行调度。

理解和掌握 Goroutine 是成为 Go 语言并发编程专家的重要一步。通过充分利用 Goroutine ,你可以更好地发挥 Go 语言的并发优势,构建出高性能、高并发的应用程序。

相关推荐
光头闪亮亮18 小时前
gozxing库-对图片中多个二维码进行识别的完整示例教程
go
召摇19 小时前
在浏览器中无缝运行Go工具:WebAssembly实战指南
后端·面试·go
王中阳Go2 天前
我发现不管是Java还是Golang,懂AI之后,是真吃香!
后端·go·ai编程
半枫荷2 天前
二、Go语法基础(基本语法)
go
struggle20253 天前
AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
css·人工智能·typescript·go·shell·powershell
Mgx3 天前
高性能 Go 语言带 TTL 的内存缓存实现:精确过期、自动刷新、并发安全
go
考虑考虑3 天前
go格式化时间
后端·go
光头闪亮亮4 天前
ZBar 条码/二维码识别工具介绍及golang通过cmd调用ZBar从图片中批量识别二维码
go
东风t西瓜4 天前
golang项目开发环境配置
go
zhuyasen4 天前
在某些 Windows 版本,Go 1.25.x 编译出来的 exe 运行报错:此应用无法在你的电脑上运行
windows·go·编译器