Go 语言 并发编程之 goroutine 启动与调度

Go阿木 发布于 23 天前 7 次阅读


Go 语言并发编程之 goroutine 启动与调度

在Go语言中,并发编程是一种非常强大的特性,它允许程序同时执行多个任务,从而提高程序的执行效率和响应速度。goroutine是Go语言并发编程的核心概念,它是一种轻量级的线程,可以与操作系统线程并行执行。本文将围绕goroutine的启动与调度展开,深入探讨Go语言的并发编程技术。

1. goroutine 简介

goroutine是Go语言中用于并发编程的基本单位,它是由Go运行时(runtime)管理的。与传统的线程相比,goroutine具有以下特点:

- 轻量级:goroutine比线程更轻量级,其创建和销毁开销较小。

- 并行:多个goroutine可以在同一时间点并行执行。

- 调度:goroutine的执行由Go运行时进行调度。

2. goroutine 的启动

在Go语言中,可以使用`go`关键字来启动一个goroutine。以下是一个简单的示例:

go

package main

import (


"fmt"


"time"


)

func main() {


go func() {


fmt.Println("Hello, World!")


}()

time.Sleep(1 time.Second)


}


在上面的代码中,我们使用`go`关键字启动了一个新的goroutine,该goroutine会打印出“Hello, World!”。由于goroutine的执行是并行的,所以打印语句的执行顺序是不确定的。

3. goroutine 的调度

goroutine的调度是由Go运行时负责的。Go运行时使用了一个名为M(Machine)的数据结构来表示一个goroutine的执行状态。M与P(Processor)和G(Goroutine)共同构成了Go语言并发编程的核心调度机制。

- M:代表一个执行goroutine的线程。

- P:代表一个处理器,它负责管理M和G的调度。

- G:代表一个goroutine,它包含goroutine的执行状态。

Go运行时使用以下策略来调度goroutine:

1. 工作窃取(Work Stealing):当一个P没有可执行的goroutine时,它会从其他P那里窃取goroutine来执行。

2. 全局队列:当P创建一个新的goroutine时,如果当前P的本地队列已满,则将G放入全局队列。

3. 本地队列:每个P都有一个本地队列,用于存储等待执行的goroutine。

以下是一个简单的示例,展示了goroutine的调度过程:

go

package main

import (


"fmt"


"sync"


"time"


)

func main() {


var wg sync.WaitGroup


for i := 0; i < 10; i++ {


wg.Add(1)


go func(id int) {


defer wg.Done()


fmt.Printf("Goroutine %d is running", id)


time.Sleep(time.Millisecond 100)


}(i)


}

wg.Wait()


}


在上面的代码中,我们创建了10个goroutine,每个goroutine都会打印出其ID并休眠100毫秒。由于goroutine的执行是并行的,所以打印语句的执行顺序是不确定的。Go运行时会根据调度策略来决定每个goroutine的执行顺序。

4. goroutine 的同步

在并发编程中,goroutine之间的同步是非常重要的。Go语言提供了多种同步机制,如通道(channel)、互斥锁(mutex)、条件变量(condition)等。

以下是一个使用通道进行goroutine同步的示例:

go

package main

import (


"fmt"


"sync"


"time"


)

func main() {


done := make(chan bool)


var wg sync.WaitGroup

for i := 0; i < 5; i++ {


wg.Add(1)


go func(id int) {


defer wg.Done()


fmt.Printf("Goroutine %d is starting", id)


time.Sleep(time.Millisecond 100)


fmt.Printf("Goroutine %d is done", id)


done <- true


}(i)


}

wg.Wait()


fmt.Println("All goroutines are done")


<-done


}


在上面的代码中,我们使用了一个通道`done`来同步goroutine的执行。每个goroutine在完成执行后,都会向通道发送一个`true`值。主goroutine等待所有goroutine完成执行,然后打印出“All goroutines are done”,最后从通道中读取一个值,确保所有goroutine都已经完成。

5. 总结

goroutine是Go语言并发编程的核心概念,它允许程序同时执行多个任务,从而提高程序的执行效率和响应速度。本文介绍了goroutine的启动与调度机制,并展示了如何使用goroutine进行同步。通过掌握这些技术,开发者可以编写出高效、可靠的并发程序。

在Go语言的并发编程中,还有很多其他高级特性,如context、select语句、原子操作等,这些特性可以帮助开发者更好地控制并发程序的行为。随着Go语言的不断发展,相信会有更多优秀的并发编程技术出现,为开发者提供更强大的工具。