Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
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
Archives
Today
Total
관리 메뉴

Code Habit

Go ) Select 본문

카테고리 없음

Go ) Select

코드베어 2020. 6. 10. 08:12

Go 언어는 여러 채널을 손쉽게 사용할 수 있도록 select 분기문을 제공한다.

- select { case <- 채널 : 코드 }

1
2
3
4
5
6
7
8
select {
case <- 채널1:
    // 채널1에 값이 들어왔을 때 실행할 코드를 작성한다.
case <- 채널2:
    // 채널2에 값이 들어왔을 때 실행할 코드를 작성한다.
default:
    // 모든 case의 채널에 값이 들어오지 않았을 때 실행할 코드를 작성합니다.
}

 

select 분기문은 switch 분기문과 비슷하지만 select 키워드 뒤에 검사할 변수를 따로 지정하지 않으며 각 채널에 값이 들어오면 해당 case가 실행된다. ( close 함수로 채널을 닫았을 때도 case가 실행된다. ) 그리고 보통 select를 계속 처리할 수 있도록 for로 반복해준다. (반복하지 않으면 한 번만 실행하고 끝낸다.)

default에 적절한 처리를 하지 않으면 CPU 코어를 모두 점유하므로 주의하자 !!

 

다음은 select 분기문을 활용한 예제이다.

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
30
31
32
33
34
35
36
37
38
package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    c1 := make(chan int)    // int형 채널 생성
    c2 := make(chan string// string형 채널 생성
 
    go func() {
        for {
            c1 <- 10                            // 채널 c1에 10을 보낸 뒤
            time.Sleep(100 * time.Millisecond)    // 100 밀리초 대기
        }
    }()
 
    go func() {
        for {
            c2 <- "Hello, world!"                // 채널 c2에 Hello, world!를 보낸 뒤
            time.Sleep(500 * time.Millisecond)    // 500 밀리초 대기
        }
    }()
 
    go func() {
        for {
            select {
            case i := <- c1:    // 채널 c1에 값이 들어왔다면 값을 꺼내서 i에 대입
                fmt.Println("c1 :", i)
            case s := <- c2:    // 채널 c2에 값이 들어왔다면 값을 꺼내서 s에 대입    
                fmt.Println("c2 :", s)
            }
        }
    }()
 
    time.Sleep(10 * time.Second) // 10초 동안 프로그램 실행
}

case에서는 case i := <- c1: 처럼 채널에서 값을 꺼낸 뒤 변수에 바로 저장할 수 있다. 만약 꺼낸 값을 사용하지 않는다면 case <- c1: 처럼 변수를 생략해도 된다.

 

실행 결과

c1 : 10
c2 : Hello, world!
c1 : 10
c1 : 10
c1 : 10
c1 : 10
c2 : Hello, world!
c1 : 10
c1 : 10
c1 : 10
...

 

select 분기문은 채널에 값을 보낼 수도 있다.

- case 채널 <- 값: 코드

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
30
31
32
33
34
35
36
37
38
package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    c1 := make(chan int)    // int형 채널 생성
    c2 := make(chan string// string형 채널 생성
 
    go func() {
        for {                                    // 무한 루프
            i := <- c1                            // 채널 c1에서 값을 꺼낸 뒤 i에 대입
            fmt.Println("c1 :", i)                // i 값을 출력
            time.Sleep(100 * time.Millisecond)    // 100 밀리초 대기
        }
    }()
 
    go func() {
        for {                                    // 무한루프
            c2 <- "Hello, world!"                // 채널 c2에 Hello, world!를 보낸 뒤
            time.Sleep(500 * time.Millisecond)    // 500 밀리초 대기
        }
    }()
 
    go func() {
        for {                    // 무한루프
            select {
            case c1 <- 10:      // 매번 채널 c1에 10을 보냄
            case s := <- c2:    // 채널 c2에 값이 들어왔다면 값을 꺼내서 s에 대입    
                fmt.Println("c2 :", s)
            }
        }
    }()
 
    time.Sleep(10 * time.Second) // 10초 동안 프로그램 실행
}

 

실행 결과

c2 : Hello, world!
c1 : 10
c1 : 10
c1 : 10
c1 : 10
c1 : 10
c2 : Hello, world!
c1 : 10
c1 : 10
...

 

예제에서는 c1, c2 두개의 채널을 사용했지만 채널 c1 한개로 select에서 값을 보내거나 받을 수도 있다.