본문 바로가기
golang

golang cancel과 waitGroup 기초

by PudgeKim 2021. 4. 11.

이번 글에서는 여러개의 고루틴을 제어하는 기초방법들 중 하나를 소개하겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main
 
import (
    "context"
    "fmt"
    "sync"
)
 
func PrintNum(ctx context.Context, num int, wg *sync.WaitGroup) {
    defer wg.Done() // 고루틴이 끝났다고 알림
    if ctx.Err() == context.Canceled { 
        fmt.Println(num, " canceled")
        return
    }
    fmt.Println(num, "executed")
}
 
func main() {
    wg := &sync.WaitGroup{} 
    ctx, cancel := context.WithCancel(context.Background())
    for i:=0; i<10; i++ {
        go PrintNum(ctx, i, wg)
        wg.Add(1// 고루틴이 하나 추가되었다고 알림
    }
    cancel()
    wg.Wait() // 고루틴이 모두 끝날때까지 대기 
 
 
}
cs

위 예제는 10개의 고루틴을 실행하는데 각 고루틴들은 cancel이 되었다면 "canceled"를 출력하고 cancel이 되기전에 실행되었다면
"executed"를 출력하게 됩니다.

&sync.WaitGroup을 통해 고루틴들을 관리할 준비를 합니다. 그리고 context.WithCancel을 통해 각 고루틴들에게 cancel 여부를 알릴 수 있습니다. (물론 위 코드에서 보다시피 함수의 인자로 context가 필요합니다.)

cancel 여부는 context함수의 에러를 통해 알 수 있습니다.

아래는 위 코드 실행 결과의 예입니다. (고루틴 특성상 실행결과가 계속 달라집니다.)

실행 결과를 보면 0번과 2번 고루틴은 cancel 함수가 실행되기전에 실행되었고 나머지 고루틴들은 cancel 이후에 실행된 것을 확인할 수 있습니다.

 

그러나 보통은 wg.Done 함수를 이용해서 제어합니다. 아래 예제를 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main
 
import (
    "context"
    "fmt"
    "sync"
    "time"
)
 
func PrintAfterThree(ctx context.Context, wg *sync.WaitGroup) {
    defer wg.Done()
    select {
    case <- time.After(3*time.Second):
        fmt.Println("3 seconds elapsed...")
    case <- ctx.Done():
        fmt.Println("canceled..")
    }
}
func main() {
    wg := &sync.WaitGroup{}
    ctx, cancel := context.WithCancel(context.Background())
    wg.Add(1)
    go PrintAfterThree(ctx, wg)
    time.Sleep(2*time.Second)
    cancel()
    wg.Wait()
 
}
cs

context.Done 함수는 cancel 함수가 실행되면 struct{} (empty struct)를 채널로 보내 신호를 줍니다.

위 예제에서는 PrintAfterThree 함수가 2초가 지나고(main function에 time.Sleep) cancel 신호를 받기 때문에
"canceled"가 출력됩니다. 

만약 main function에서 time.Sleep을 3초보다 크게 준다면 cancel 신호 이전에 time.After신호를 먼저 받을테니 
"3 seconds elapsed..."가 출력될 것입니다.

 

이렇게 cancel 신호를 이용하여 고루틴을 제어할 수 있습니다.

'golang' 카테고리의 다른 글

golang network udp connection 기초  (0) 2021.04.17
Golang network#2 tcp buffer  (0) 2021.04.12
golang signal과 context 기초  (0) 2021.04.06
Golang network TCP hello world 예제  (0) 2021.04.05
golang에서 heap 사용하기  (0) 2021.04.03