SyMind / learning

路漫漫其修远兮,吾将上下而求索。
10 stars 1 forks source link

Go 语言中如何并行执行多个函数 #43

Open SyMind opened 2 years ago

SyMind commented 2 years ago

原文:https://www.digitalocean.com/community/tutorials/how-to-run-multiple-functions-concurrently-in-go

介绍

Go 中的两个特性,goroutines 和 channels,在一起使用时使并发更容易。 Goroutine 解决了在程序中设置和运行并发代码的困难,通道解决了并发运行的代码之间安全通信的困难。

使用 Goroutine 并行执行函数

Go 执行此操作的一种方法是使用称为 goroutine 的功能。 goroutine 是一种特殊类型的函数,可以在其他 goroutine 也在运行时运行。当一个程序被设计为一次运行多个代码流时,该程序被设计为同时运行。通常,当一个函数被调用时,它会在它继续运行之后完全在代码之前完成运行。这被称为在“前台”运行,因为它会阻止您的程序在完成之前执行任何其他操作。使用 goroutine,当 goroutine 在“后台”运行时,函数调用将立即继续运行下一个代码。当代码在完成之前不阻止其他代码运行时,它被视为在后台运行。

在 main.go 文件中粘贴或键入以下代码以开始使用。

package main

import (
    "fmt"
)

func generateNumbers(total int) {
    for idx := 1; idx <= total; idx++ {
        fmt.Printf("Generating number %d\n", idx)
    }
}

func printNumbers() {
    for idx := 1; idx <= 3; idx++ {
        fmt.Printf("Printing number %d\n", idx)
    }
}

func main() {
    printNumbers()
    generateNumbers(3)
}

这个初始程序定义了两个函数,generateNumbers 和 printNumbers,然后在 main 函数中运行这些函数。 generateNumbers 函数将要“生成”的数字数量作为参数,在本例中为 1 到 3,然后将这些数字中的每一个打印到屏幕上。 printNumbers 函数还没有接受任何参数,但它也会打印出数字 1 到 3。

package main

import (
    "fmt"
    "sync"
)

func generateNumbers(total int, wg *sync.WaitGroup) {
    defer wg.Done()

    for idx := 1; idx <= total; idx++ {
        fmt.Printf("Generating number %d\n", idx)
    }
}

func printNumbers(wg *sync.WaitGroup) {
    defer wg.Done()

    for idx := 1; idx <= 3; idx++ {
        fmt.Printf("Printing number %d\n", idx)
    }
}

func main() {
    var wg sync.WaitGroup

    wg.Add(2)
    go printNumbers(&wg)
    go generateNumbers(3, &wg)

    fmt.Println("Waiting for goroutines to finish...")
    wg.Wait()
    fmt.Println("Done!")
}

使用 Channel 在 Goroutine 间安全地进行通信

并发编程中比较困难的部分之一是在同时运行的程序的不同部分之间进行安全通信。如果你不小心,你可能会遇到只有并发程序才有可能出现的问题。例如,当程序的两个部分同时运行时,可能会发生数据竞争,其中一部分尝试更新变量,而另一部分同时尝试读取它。发生这种情况时,读取或写入可能会发生乱序,导致程序的一个或两个部分使用错误的值。 “数据竞赛”这个名称来自程序的两个部分相互“竞赛”以访问数据。