> 백엔드 개발 > Golang > Golang의 WaitGroup 트랩을 분석하고 문제를 해결합니다.

Golang의 WaitGroup 트랩을 분석하고 문제를 해결합니다.

藏色散人
풀어 주다: 2021-09-14 15:57:02
앞으로
2020명이 탐색했습니다.

이 글은 Golang의 WaitGroup 트랩을 소개하기 위해 go 언어 튜토리얼 칼럼에서 작성되었습니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

sync.WaitGroup은 동시성 환경에서 매우 일반적인 데이터 구조로, 모든 코루틴이 끝날 때까지 기다리는 데 사용됩니다. 예이며 사용법을 자세히 알아볼 필요가 없습니다. 며칠 전, 코루틴에서 Add() 함수를 실행할 수 있는지 궁금했습니다. 대답은 '아니오'입니다. sync.WaitGroup是并发环境中,一个相当常用的数据结构,用来等待所有协程的结束,在写代码的时候都是按着例子的样子写的,也没用深究过它的使用。前几日想着能不能在协程中执行Add()函数,答案是不能,这里介绍下。

陷阱在WaitGroup的3个函数的调用顺序上。先回顾下3个函数的功能:

  1. Add(delta int):给计数器增加delta,比如启动1个协程就增加1。
  2. Done():协程退出前执行,把计数器减1。
  3. Wait():阻塞等待计数器为0。

考一考

下面的程序是创建了协程father,然后father协程创建了10个子协程,main函数等待所有协程结束后退出,看看下面代码有没有什么问题?

package main

import (
    "fmt"
    "sync"
)

func father(wg *sync.WaitGroup) {
    wg.Add(1)
    defer wg.Done()

    fmt.Printf("father\n")
    for i := 0; i < 10; i++ {
        go child(wg, i)
    }
}

func child(wg *sync.WaitGroup, id int) {
    wg.Add(1)
    defer wg.Done()

    fmt.Printf("child [%d]\n", id)
}

func main() {
    var wg sync.WaitGroup
    go father(&wg)

    wg.Wait()
    log.Printf("main: father and all chindren exit")
}
로그인 후 복사

发现问题了吗?如果没有看下面的运行结果:main函数在子协程结束前就开始结束了。

father
main: father and all chindren exit
child [9]
child [0]
child [4]
child [7]
child [8]
로그인 후 복사

陷阱分析

产生以上问题的原因在于,创建协程后在协程内才执行Add()函数,而此时Wait()函数可能已经在执行,甚至Wait()函数在所有Add()执行前就执行了,Wait()

함정은 WaitGroup의 세 가지 함수 호출 순서에 있습니다. 먼저 세 가지 함수의 기능을 검토해 보겠습니다.

  1. Add(delta int): 카운터에 델타를 추가합니다. 예를 들어 코루틴을 시작할 때 1씩 증가시킵니다.
  2. Done(): 코루틴이 종료되기 전에 실행되어 카운터를 1씩 감소시킵니다.
  3. Wait(): 차단 대기 카운터는 0입니다.

테스트해 보세요

다음 프로그램은 코루틴 아버지를 생성하고, 아버지 코루틴은 10개의 하위 코루틴을 생성한 후 모든 코루틴이 완료될 때까지 기다린 후 코드를 확인합니다. 아래. 문제 없나요?

package main

import (
    "fmt"
    "sync"
)

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

    fmt.Printf("father\n")
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go child(wg, i)
    }
}

func child(wg *sync.WaitGroup, id int) {
    defer wg.Done()
    fmt.Printf("child [%d]\n", id)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go father(&wg)

    wg.Wait()
    fmt.Println("main: father and all chindren exit")
}
로그인 후 복사
문제를 찾으셨나요? 다음 실행 결과가 표시되지 않으면 하위 코루틴이 종료되기 전에 기본 함수가 종료되기 시작합니다.
father
child [9]
child [7]
child [8]
child [1]
child [4]
child [5]
child [2]
child [6]
child [0]
child [3]
main: father and all chindren exit
로그인 후 복사
트랩 분석

위 문제가 발생하는 이유는 코루틴이 생성된 후 코루틴 내에서 Add() 함수가 실행되는데 이때 Wait() 함수 <p>Maybe</p>가 이미 실행 중이거나 모든 <code>Add()가 실행되기 전에 Wait() 함수도 실행되고 Wait가 실행되는 즉시 ()가 실행됩니다. WaitGroup의 카운터가 0이 되면 Wait가 종료되고 메인 프로그램이 종료됩니다. 결과적으로 모든 하위 코루틴이 완전히 종료되지 않고 메인 기능이 종료됩니다.
🎜올바른 접근 방식🎜🎜🎜Add 함수는 Wait 함수가 실행되기 전에 실행되어야 합니다🎜 이는 Add 함수 문서에서 제안됩니다. 🎜카운터가 0일 때 발생하는 양의 델타가 있는 호출이 발생해야 합니다. 기다리기 전에.🎜. 🎜🎜기다림 기능 전에 추가 기능이 실행되어야 하는지 어떻게 확인할 수 있나요? 코루틴의 경우 코루틴에 있는 코드의 실행 시간이 Wait 함수의 실행 시간보다 빠른지 여부를 예측할 수 없습니다. 그러나 Coroutine을 할당하기 전에 Add 함수를 실행한 후 Wait를 실행하면 이를 확인할 수 있습니다. 기능. 🎜🎜다음은 수정된 프로그램과 출력 결과입니다. 🎜rreerrree🎜

위 내용은 Golang의 WaitGroup 트랩을 분석하고 문제를 해결합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:segmentfault.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿