📜  在Golang中使用WaitGroup

📅  最后修改于: 2021-05-20 06:25:29             🧑  作者: Mango

Go例程对于golang来说是一个很好的卖点,这使它成为众多开发人员的选择。在这篇文章中,我们将看到这些goroutine的一个常见问题,并尝试解决它。

让我们看一个说明此问题的简单代码片段,

Go
package main
  
import "fmt"
  
func runner1() {
    fmt.Print("\nI am first runner")
}
  
func runner2() {
    fmt.Print("\nI am second runner")
}
  
func execute() {
    go runner1()
    go runner2()
  
}
  
func main() {
    
    // Launching both the runners
    execute()
}


Go
package main
  
import (
    "fmt"
    "time"
)
  
func runner1() {
    fmt.Print("\nI am first runner")
}
  
func runner2() {
    fmt.Print("\nI am second runner")
}
  
func execute() {
    go runner1()
    go runner2()
  
}
  
func main() {
  
    // Launching both the runners
    execute()
    time.Sleep(time.Second)
}


Go
package main
  
import (
    "fmt"
    "sync"
)
  
func runner1(wg *sync.WaitGroup) {
    defer wg.Done() // This decreases counter by 1
    fmt.Print("\nI am first runner")
  
}
  
func runner2(wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Print("\nI am second runner")
}
  
func execute() {
    wg := new(sync.WaitGroup)
    wg.Add(2)
  
    // We are increasing the counter by 2
    // because we have 2 goroutines
    go runner1(wg)
    go runner2(wg)
  
    // This Blocks the execution
    // until its counter become 0
    wg.Wait()
}
  
func main() {
    // Launching both the runners
    execute()
}


如您所见,输出中没有任何内容,这是因为一旦启动两个goroutine,主函数便会终止。 Golang中的每个程序都会执行,直到主函数没有终止。那么,我们该怎么办

1.我们可以在启动跑步者之后等待一段时间,为此,我们将使用“时间”包函数“睡眠”,该函数在给定持续时间内暂停执行该功能,

package main
  
import (
    "fmt"
    "time"
)
  
func runner1() {
    fmt.Print("\nI am first runner")
}
  
func runner2() {
    fmt.Print("\nI am second runner")
}
  
func execute() {
    go runner1()
    go runner2()
  
}
  
func main() {
  
    // Launching both the runners
    execute()
    time.Sleep(time.Second)
}

输出:

I am second runner
I am first runner

我们只是解决了这个问题,在启动跑步者之后,我们等待一秒钟,因此我们的主要函数是睡眠(阻止)1秒钟。在此期间,所有执行例程均已成功执行。但是Golang是一种快速的语言,仅打印2个字符串就不需要1秒钟的时间。

问题在于,我们的执行程序执行的时间很少,因此我们不必要地阻塞了程序1秒钟。在此示例中,这似乎不是一个关键问题,但是如果您要生产将同时满足1000个请求的生产级服务器,这将是一个大问题。

2.让我们使用另一个Golang的标准库原语“ sync.WaitGroup ”。 WaitGroup实际上是一种计数器,它会阻止函数(或者可能会说一个Goroutine)的执行,直到其内部计数器变为0为止。

这个怎么运作 ?

WaitGroup导出3种方法。

1 Add(int)  It increases WaitGroup counter by given integer value.
2 Done()  It decreases WaitGroup counter by 1, we will use it to indicate termination of a goroutine.
3 Wait() It Blocks the execution until it’s internal counter becomes 0.

注意:WaitGroup是并发安全的,因此可以安全地将指向它的指针作为Groutines的参数传递。

package main
  
import (
    "fmt"
    "sync"
)
  
func runner1(wg *sync.WaitGroup) {
    defer wg.Done() // This decreases counter by 1
    fmt.Print("\nI am first runner")
  
}
  
func runner2(wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Print("\nI am second runner")
}
  
func execute() {
    wg := new(sync.WaitGroup)
    wg.Add(2)
  
    // We are increasing the counter by 2
    // because we have 2 goroutines
    go runner1(wg)
    go runner2(wg)
  
    // This Blocks the execution
    // until its counter become 0
    wg.Wait()
}
  
func main() {
    // Launching both the runners
    execute()
}

输出:

I am second runner
I am first runner

输出是相同的,但是我们out程序在1秒钟内没有阻塞。上面我们向您展示的模式是在Golang中编写并发代码的一种常见做法。