Fibonacci 로 알아보는 동시성 과 클로저
프로그래밍의 입문 딱지를 떼고나서 마주쳤던 몇가지 문제들중 멀티쓰레드와 클로저에 대해서 피보나치로 파헤쳐 보려고합니다.
동시성을 이용한 구현
func fibonacci(max int) <-chan int {
c := make(chan int)
go func() {
defer close(c)
a, b := 0, 1
for a <= max {
c <- a
a, b = b, a+b
}
}()
return c
}
클로저를 이용한 구현
func fibonacci(max int) <-chan int {
c := make(chan int)
go func() {
defer close(c)
a, b := 0, 1
for a <= max {
c <- a
a, b = b, a+b
}
}()
return c
}
실행
func main() {
for fib := range fibonacci(15) {
fmt.Printf("%d, ", fib)
}
fmt.Println()
fib := fibonacciClosure(15)
for n := fib(); n >= 0; n = fib() {
fmt.Printf("%d, ", n)
}
}
둘다 같은 값을 출력합니다.
일단 클로저 부터 파헤쳐 보자면 Go 언어에서 함수는 Closure로서 사용될 수도 있습니다.
Closure는 함수 외부의 변수를 참조하는 함수값(fucntion value)를 일컫는데 이때 함수의 바깥의 변수를 마치 함수안에서 그대로 그 변수를 읽거나 쓸수 있게 됩니다.
그래서 처음 initalize 를 하고나서 다른 변수에 다시 initalize 하지 않는 이상 그변수가 가르키는 값을 변하지 않습니다.
Goroutine 으로 구현한 피보나치를 보겠습니다. generate pattern 을 사용하여 receive 만 가능한 채널을 리턴합니다.
fibonacci 의 내부의 c라는 채널은 양방향으로 선언되어있지만 return 값은 one way입니다.
return value 를 양방향으로 줄수도 있지만 one way 로 준 이유는 외부에서
fibonacci(3) <- 3
으로 채널에 데이터를 보내게 될경우 받는 고루틴이 없어서 Deadlock 에 걸리게 됩니다.
실수를 미연에 방지하고자 return value 를 강제합니다.
차이점
비슷해보이지만 Go에서는 채널을 이용하는 방법에 몇가지 장점이 있습니다.
1. 생성하는 쪽에서 상태 저장 방법을 복잡하게 고민할 필요가 없다.
2. 받는 쪽에서 for 의 range를 이용할 수 있다.
3. 채널 버퍼를 이용하면 멀티 코어를 활용하거나 입출력 성능상의 장점을 이용할 수 있다.
'Go' 카테고리의 다른 글
Linux Set up GO PATH (0) | 2021.11.07 |
---|---|
Goroutine 정말 수백만개를 만들어도 문제 없을까? (0) | 2021.10.29 |
Publisher Subscriber pattern (발행 구독 패턴) (0) | 2021.10.25 |
Handling databases using gorm (0) | 2021.10.20 |
Go interface: 대소문자 의 의미 (0) | 2021.10.20 |
댓글
이 글 공유하기
다른 글
-
Linux Set up GO PATH
Linux Set up GO PATH
2021.11.07 -
Goroutine 정말 수백만개를 만들어도 문제 없을까?
Goroutine 정말 수백만개를 만들어도 문제 없을까?
2021.10.29 -
Publisher Subscriber pattern (발행 구독 패턴)
Publisher Subscriber pattern (발행 구독 패턴)
2021.10.25 -
Handling databases using gorm
Handling databases using gorm
2021.10.20