- 출처: https://go.dev/doc/effective_go#concurrency
- Share by communicating
동시성 프로그래밍은 매우 방대한 주제이다. 동시성 프로그래밍은 공유 변수에 대한 정확한 접근을 구현하기 위해 요구되는 미묘한 부분 때문에 어려운 주제이기도 하다. Go 언어는 공유되는 값들이 channel 이라는 개념을 통해 전달되고, 실제로는 실행되는 각 스레드들에서 공유가 활성화되지 않는 색다른 접근방식을 제안한다. 어느 시점에서든 하나의 값에는 하나의 goroutine만 접근이 가능하다. 이런 설계때문에 data race가 일어나지 않는다. effective go 문서에서는 이런 사고방식을 장려하기 위해 하나의 슬로건으로 이를 요약하고 있다.
Do not communicate by sharing memory; instead, share memory by communicating.
참조 count 변수를 구현하기 위해서 integer 변수 주위에 mutex를 넣는것이 가장 좋은 방법이 될 수는 있지만, 추상적인 관점에서는 접근을 제어하기 위해 채널은 사용하는것이 쓰기를 더 명확하게 만들어서 정확한 프로그램을 만든다고 볼 수 있다.
이런 모델을 이해하기 위한 좋은 방법은 하나의 CPU에서 실행되고 있는 전형적인 싱글 스레드 프로그램을 생각해보는것이다. 이런 프로그램은 원천적으로 동기화를 필요로 하지 않는다. 하나의 instance를 또 실행한다고 해도 이것 역시 동기화를 필요로 하지 않는다. 이제 이 둘이 통신하게 해보자. 만약 통신이 동기화 장치인 경우 여전히 다른 동기화는 필요가 없다. 예를 들어 Unix 파이프라인의 경우 이 모델에 완벽하게 들어맞는다. 비록 Go의 동시성 접근법이 Hoare의 통신 직렬 프로세스(CSP - Communicating Sequential Process)에서 유래 했지만, Unix 파이프의 type-safe 일반화로도 볼 수 있다.
- Goroutines
goroutine으로 칭한 이유는 스레드, coroutines, processes 등과 같이 기존 용어를 사용하면 부정확한 의미를 전달하기 때문이다. goroutine의 모델은 단순한데 같은 주소 공간에 다른 goroutine 들과 동시에 함수를 실행한다. goroutine은 가벼우며, stack 공간 할당보다 비용이 조금 더 발생한다. 그리고 stack은 작게 시작하므로 저렴하며 heap 공간의 요구에 따라 할당되는 공간이 점점 커질 수 있다.
goroutine은 다수의 OS 스레드에 대해 다중화되며, 만약 I/O를 기다리는것과 같이 하나 block 되어야 하는 경우 다른 goroutine은 계속해서 실행된다. 물론 이런 설계이면에는 스레드의 생성이나 관리에 대한 많은 복잡함이 캡슐화되어 있다.
goroutine을 호출하려면 함수나 메소드에 go 키워드를 접두사로 붙여주면 된다. 호출이 완료되면 goroutine 은 별도의 동작없이 종료된다. (Unix의 shell 에서 & 기호를 통해 백그라운드 실행하는것과 비슷하다.)
go list.Sort() // run list.Sort concurrently; don't wait for it.
함수 리터럴은 goroutine을 간편하게 실행하는데 유용하게 사용된다.
func Announce(message string, delay time.Duration) {
go func() {
time.Sleep(delay)
fmt.Println(message)
}() // Note the parentheses - must call the function.
}
Go에서 함수 리터럴은 클로저(closures)의 성격을 갖는다. 함수 구현부는 외부 함수가 활성상태이기만 하면 해당 함수에 의해 참조되는 변수가 살아남는것을 보장해준다.
위에서 예제 코드를 기술하긴 했지만, 완료 되어도 아무런 동작을 취하지 않거나 신호를 보내고 있지 않기 때문에 실제로 이런방식으로는 잘 사용되지 않고 channel과 함께 사용되는 경우가 대부분이다.
'Language > Go' 카테고리의 다른 글
Effective Go - Concurrency - 3 (0) | 2022.06.02 |
---|---|
Effective Go - Concurrency - 2 (0) | 2022.06.01 |
Effective Go - Embedding (0) | 2022.05.29 |
Effective Go - Interfaces and other types (0) | 2022.05.26 |
Effective Go - Methods (0) | 2022.05.17 |
댓글