Go 语言 并发编程之 goroutine 入门

Go阿木 发布于 2025-06-22 6 次阅读


Go 语言并发编程之 goroutine 入门

Go 语言以其简洁、高效和并发编程能力著称。在Go语言中,goroutine 是实现并发编程的核心机制。本文将围绕 goroutine 的概念、创建、使用和常见模式展开,帮助读者入门 Go 语言并发编程。

一、什么是 goroutine?

在Go语言中,goroutine 是轻量级的线程,是 Go 语言并发编程的基础。与传统的线程相比,goroutine 的创建和销毁更加高效,且占用资源更少。一个goroutine 可以看作是一个函数的执行实例,它可以在程序中并行执行。

二、创建 goroutine

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

go

package main

import (


"fmt"


"time"


)

func main() {


go sayHello()


time.Sleep(1 time.Second) // 等待1秒,确保goroutine执行完毕


}

func sayHello() {


fmt.Println("Hello, World!")


}


在上面的代码中,`sayHello` 函数被封装在一个 goroutine 中执行。由于 `main` 函数中调用了 `time.Sleep`,程序会等待 1 秒,确保 `sayHello` 函数中的代码执行完毕。

三、goroutine 的生命周期

goroutine 的生命周期包括以下几个阶段:

1. 创建:使用 `go` 关键字创建一个 goroutine。

2. 运行:goroutine 开始执行,直到函数返回或遇到阻塞操作。

3. 等待:当 goroutine 遇到阻塞操作(如 I/O 操作、等待其他 goroutine 等)时,它会进入等待状态。

4. 结束:goroutine 执行完毕或被终止。

四、goroutine 的使用

goroutine 的使用非常灵活,以下是一些常见的使用场景:

1. 并行计算

go

package main

import (


"fmt"


"math/rand"


"sync"


)

func main() {


var wg sync.WaitGroup


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


wg.Add(1)


go func(id int) {


defer wg.Done()


result := calculate(id)


fmt.Printf("Result of %d: %d", id, result)


}(i)


}


wg.Wait()


}

func calculate(id int) int {


time.Sleep(time.Duration(rand.Intn(1000)) time.Millisecond)


return id 2


}


在上面的代码中,我们创建了 10 个 goroutine 来并行计算结果。

2. I/O 密集型任务

go

package main

import (


"fmt"


"net/http"


"sync"


)

func main() {


var wg sync.WaitGroup


urls := []string{


"http://www.google.com",


"http://www.bing.com",


"http://www.yahoo.com",


}


for _, url := range urls {


wg.Add(1)


go func(url string) {


defer wg.Done()


resp, err := http.Get(url)


if err != nil {


fmt.Println("Error fetching URL:", url, err)


return


}


fmt.Println("Fetched URL:", url, "Status Code:", resp.StatusCode)


}(url)


}


wg.Wait()


}


在上面的代码中,我们使用 goroutine 来并行获取多个网页的响应。

3. 等待多个 goroutine 完成

go

package main

import (


"fmt"


"sync"


)

func main() {


var wg sync.WaitGroup


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


wg.Add(1)


go func(id int) {


defer wg.Done()


fmt.Println("Goroutine", id, "is running")


time.Sleep(time.Duration(rand.Intn(1000)) time.Millisecond)


}(i)


}


wg.Wait()


fmt.Println("All goroutines have completed")


}


在上面的代码中,我们使用 `sync.WaitGroup` 来等待所有 goroutine 完成。

五、goroutine 的常见模式

1. WaitGroup

`sync.WaitGroup` 是一个同步原语,用于等待一组 goroutine 完成。在上面的示例中,我们已经使用了 `WaitGroup`。

2. Channel

Channel 是 Go 语言中用于 goroutine 间通信的机制。以下是一个使用 channel 的示例:

go

package main

import (


"fmt"


"sync"


)

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.Println("Goroutine", id, "is running")


time.Sleep(time.Duration(rand.Intn(1000)) time.Millisecond)


done <- true


}(i)


}


wg.Wait()


close(done)


fmt.Println("All goroutines have completed")


for _ := range done {


fmt.Println("Goroutine has completed")


}


}


在上面的代码中,我们使用 channel `done` 来通知主 goroutine 所有子 goroutine 都已完成。

3. Context

`context` 包提供了一种取消信号和截止时间的传递机制,可以用于控制 goroutine 的执行。以下是一个使用 context 的示例:

go

package main

import (


"context"


"fmt"


"time"


)

func main() {


ctx, cancel := context.WithTimeout(context.Background(), 2time.Second)


defer cancel()


go func() {


fmt.Println("Goroutine is running")


time.Sleep(3 time.Second)


fmt.Println("Goroutine is done")


}()

select {


case <-ctx.Done():


fmt.Println("Operation timed out")


}


}


在上面的代码中,我们使用 `context.WithTimeout` 创建了一个带有超时的 context,如果子 goroutine 在 2 秒内没有完成,主 goroutine 将收到一个取消信号。

六、总结

goroutine 是 Go 语言并发编程的核心机制,它为开发者提供了高效、灵活的并发编程能力。通过本文的学习,读者应该对 goroutine 的概念、创建、使用和常见模式有了初步的了解。在实际开发中,合理地使用 goroutine 可以提高程序的并发性能,但也要注意避免常见的并发问题,如竞态条件、死锁等。