sync.WaitGroup의 예가 맞습니까?
이 예제 사용법이 sync.WaitGroup
맞습니까? 예상 된 결과를 제공하지만의 wg.Add(4)
및 위치에 대해 잘 모르겠습니다 wg.Done()
. 4 개의 고 루틴을 한 번에 추가하는 것이 합리적 wg.Add()
입니까?
http://play.golang.org/p/ecvYHiie0P
package main
import (
"fmt"
"sync"
"time"
)
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
duration := millisecs * time.Millisecond
time.Sleep(duration)
fmt.Println("Function in background, duration:", duration)
wg.Done()
}
func main() {
var wg sync.WaitGroup
wg.Add(4)
go dosomething(200, &wg)
go dosomething(400, &wg)
go dosomething(150, &wg)
go dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
결과 (예상대로) :
Function in background, duration: 150ms
Function in background, duration: 200ms
Function in background, duration: 400ms
Function in background, duration: 600ms
Done
예,이 예가 맞습니다. 경합 상태를 방지 wg.Add()
하기 위해 go
문 앞에 발생 하는 것이 중요합니다 . 다음도 정확합니다.
func main() {
var wg sync.WaitGroup
wg.Add(1)
go dosomething(200, &wg)
wg.Add(1)
go dosomething(400, &wg)
wg.Add(1)
go dosomething(150, &wg)
wg.Add(1)
go dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
그러나 wg.Add
이미 몇 번 호출 될 것인지 이미 알고있을 때 계속해서 호출하는 것은 의미가 없습니다.
Waitgroups
카운터가 0 아래로 떨어지면 패닉. 카운터는 0에서 시작하고 각각 Done()
은 a -1
이며 각각 Add()
은 매개 변수에 따라 다릅니다. 그래서, 카운터가 결코 아래로 떨어질없고 피할 패닉 수 있도록, 당신은이 필요로 Add()
하는 보장 전과 와서 Done()
.
Go에서 이러한 보장은 메모리 모델에 의해 제공됩니다 .
The memory model states that all statements in a single goroutine appear to be executed in the same order as they are written. It is possible that they won't actually be in that order, but the outcome will be as if it was. It is also guaranteed that a goroutine doesn't run until after the go
statement that calls it. Since the Add()
occurs before the go
statement and the go
statement occurs before the Done()
, we know the Add()
occurs before the Done()
.
If you were to have the go
statement come before the Add()
, the program may operate correctly. However, it would be a race condition because it would not be guaranteed.
I would recommend embeding the wg.Add()
call into the doSomething()
function itself, so that if you adjust the number of times it's called, you don't have to separately adjust the add parameter manually which could lead to an error if you update one but forget to update the other (in this trivial example that is unlikely, but still, I personally believe it to be better practice for code re-use).
As Stephen Weinberg points out in his answer to this question, you do have to increment the waitgroup prior to spawning the gofunc, but you can accomplish this easily by wrapping the gofunc spawn inside the doSomething()
function itself, like this:
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
duration := millisecs * time.Millisecond
time.Sleep(duration)
fmt.Println("Function in background, duration:", duration)
wg.Done()
}()
}
Then you can call it without the go
invocation, e.g.:
func main() {
var wg sync.WaitGroup
dosomething(200, &wg)
dosomething(400, &wg)
dosomething(150, &wg)
dosomething(600, &wg)
wg.Wait()
fmt.Println("Done")
}
As a playground: http://play.golang.org/p/WZcprjpHa_
- small improvement based on Mroth answer
- using defer for Done is safer
func dosomething(millisecs time.Duration, wg *sync.WaitGroup) { wg.Add(1) go func() { defer wg.Done() duration := millisecs * time.Millisecond time.Sleep(duration) fmt.Println("Function in background, duration:", duration) }() } func main() { var wg sync.WaitGroup dosomething(200, &wg) dosomething(400, &wg) dosomething(150, &wg) dosomething(600, &wg) wg.Wait() fmt.Println("Done") }
참고URL : https://stackoverflow.com/questions/19208725/example-for-sync-waitgroup-correct
'program story' 카테고리의 다른 글
스타일이 충돌하지 않도록 Twitter Bootstrap의 네임 스페이스를 지정하는 방법 (0) | 2020.08.19 |
---|---|
파일 경로에서 유니 코드 이스케이프에 대해 SyntaxError가 발생하는 이유는 무엇입니까? (0) | 2020.08.19 |
PostgreSQL이 정확히 알려주는 것은 무엇입니까? (0) | 2020.08.19 |
대부분의 최신 시스템에서 스택 성장 방향은 무엇입니까? (0) | 2020.08.19 |
Excel OleDb를 사용하여 시트 순서로 시트 이름 가져 오기 (0) | 2020.08.18 |