Golang 채널 - Go series(14)
Categories: Golang
채널
채널은 데이터를 주고받는 곳이다. make()를 이용하여 생성이 되어야 하고 채널 연산자 <-
를 따로 사용한다. 흔히 고루틴 사이에 데이터를 전송하기 위해서 사용한다. 별도의 lock이 필요없이 상대편이 필요할 때 까지 채널에서 대기한다.
package main
func main(){
ch := make(chan int) // chan은 채널, int는 정수형, 즉 정수형 채널 생성
go func(){
ch<-12345
}()
num := <- ch
println(num)
}
또한 일종의 채널의 속성으로 Go 루틴이 끝날 때 까지 기다리는 기능을 구현할 수 있다.
func main(){
done := make(chan bool)
go func(){
for i := 0; i<10; i++{
println(i)
}
done<-true
}()
<-done
}
채널 버퍼링
위에서의 예제는 Unbuffered Channel(하나의 수신자가 데이터를 받을 때 까지 묶임) 이지만,
Bufferend Channel도 있다. 이는 make(chan type, N)
을 통해 생성되는데, N
에는 사용할 버퍼의 개수를 입력한다.
아래 예제는 에러가 발생한다.
func main(){
channel := make(chan int)
channel <- 123 // (2)
println("히히힝")
}
이는 수신하는 고루틴이 없어서 (2) 부분에서 흐름이 멈추기 때문이다. 하지만 버퍼드 채널은 어떨까
func main(){
channel := make(chan int, 1)
channel <- 123
println(<-channel)
}
이는 channel 자체에 하나의 버퍼가 내장되어있어서, 하나를 저장하고도 다음 차례로 넘길 수가 있게 되어 에러가 없는 것이다.
채널 파라미터
채널에는 파라미터도 존재할 수 있다. 일반적으로 송수신을 모두 하는 채널을 전달하지만, 특별히 해당 채널로 통신을 할 것인지 혹은 수신할 것인지를 지정할 수도 있다. 송신 파라미터는 p chan <- int
와 같이 chan <-
을 사용하고 수신은 p <- chan int
와 같이 사용한다.
func main() {
ch := make(chan int,1)
sendChan(ch)
receiveChan(ch)
}
func sendChan(ch chan <- int) {
ch <- 123
}
func receiveChan(ch <- chan int) {
data := <-ch
println(data)
}
채널 close
close 함수를 이용하여 채널을 닫을 수 있는데, 더이상 송신은 안되지만 남은 버퍼만큼의 수신은 가능하다. 또한 리턴값이 두 개인데, 두 개중 두 번째로 리턴되는 값이 수신 true/false를 나타낸다.
func main(){
ch:= make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
println(<-ch)
println(<-ch)
if _, isSuccess := <-ch; !isSuccess{
println("X")
}
}
range문을 사용한 채널
다음과 같이 사용하면, 채널이 닫히면 자동적으로 루프는 사라진다.
func main(){
ch:= make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
for i := range ch {
println(i)
}
}
select 문
복수 채널들을 기다리면서 준비된 채널을 실행하는 기능을 제공한다. 여러개의 case 문에서 각각 다른 채널을 기다리다가 준비가 된 채널 case를 실행하는 것이다. 채널이 준비되지 않으면 계속 대기하게 되며 가장 먼저 도착한 채널의 case를 진행한다. default문이 있다면 계속 대기하지는 않는다.
import "time"
func main(){
isDone1 := make(chan bool)
isDone2 := make(chan bool)
go firstRoutine(isDone1)
go secondRoutine(isDone2)
EXIT:
for{
select {
case <-isDone1:
println("1은 끝")
case <-isDone2:
println("2도 끝")
break EXIT
default:
println("아직임")
}
}
}
func firstRoutine(ch chan bool){
time.sleep(1 * time.Second)
ch <- true
}
func secondRoutine(ch chan bool){
time.sleep(2 * time.Second)
ch <- true
}
Leave a comment