c语言编程笔录

首页 >   > 笔记大全

笔记大全

Go语言中goroutine和WaitGroup如何使用

更新时间:2023-12-08

什么是goroutine

在Go语言中,goroutine是一种轻量级线程的概念,它的启动开销极小,每个goroutine仅需占用一个很小的栈空间(大概只有若干KB)。由于goroutine是非常轻量级的,因此我们可以在同一进程中启动成千上万个goroutine而不会导致系统资源的枯竭,从而实现高并发的处理。

package main

import (
    "fmt"
    "time"
)

func main() {
    go func() {
        fmt.Println("goroutine1 start")
        time.Sleep(2 * time.Second)
        fmt.Println("goroutine1 done")
    }()

    go func() {
        fmt.Println("goroutine2 start")
        time.Sleep(1 * time.Second)
        fmt.Println("goroutine2 done")
    }()

    time.Sleep(3 * time.Second)
    fmt.Println("main done")
}

上面的代码启动了两个goroutine来并发执行,每个goroutine都会等待一段时间后输出一段信息。在main函数中,我们通过time.Sleep()函数来等待所有的goroutine都执行完成。上面的代码中,我们可以看到启动goroutine的方式非常简单,只需要在函数前面增加一个go关键字即可。这意味着该函数会被编译成一个goroutine,并在执行时和其他goroutine并发运行。

什么是WaitGroup

在多个goroutine同时工作时,可能需要控制这些goroutine的完成顺序。为了实现这一目的,Go语言提供了一个叫做WaitGroup的工具。它可以用来阻塞并等待一组goroutine全部完成。

使用WaitGroup非常简单,我们只需要先用Add()方法增加要等待的goroutine数量,然后在每个goroutine执行完成时调用Done()方法来通知WaitGroup减少一个应等待的goroutine数量。最后,我们可以调用Wait()方法来阻塞等待所有的goroutine完成。

package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers done")
}

上面的代码中,我们定义了一个worker函数,该函数会在启动时打印出一个消息、等待一段时间、然后再打印出一个消息。我们在main函数中创建了5个goroutine,并用WaitGroup来阻塞等待它们全部执行完毕。

goroutine和WaitGroup的组合使用

我们可以将goroutine和WaitGroup结合起来使用,实现并发操作,同时还可以控制它们的工作流。下面的示例演示了如何在多个goroutine并发执行时,使用WaitGroup来阻塞等待所有goroutine执行完成。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            fmt.Printf("Worker %d starting\n", id)
            // 模拟工作
            for j := 0; j < 10000000; j++ {

            }
            fmt.Printf("Worker %d done\n", id)
            wg.Done()
        }(i)
    }

    wg.Wait()
    fmt.Println("All workers done")
}

上面的示例中,我们创建了10个goroutine,并使用WaitGroup来阻塞等待它们全部执行完毕。

总结

Go语言的goroutine和WaitGroup是实现高效并发的重要工具。goroutine提供了轻量级线程的支持,使得我们能够在一个进程中并发执行大量任务,从而提高应用程序的性能和吞吐量。而WaitGroup则是阻塞式地等待多个goroutine执行完成的工具,可以保证多个goroutine的执行顺序和结果的正确性。

同时,我们还应当注意在使用goroutine时,避免过多地创建goroutine导致系统资源的枯竭,以及避免出现竞争条件和死锁等并发问题。