Go의 동시성 프로그래밍

October 28, 2024

스레드란

고루틴은 경량 스레드로서, 함수나 명령을 동시에 실행할때 사용한다. 프로세스는 한 개 이상의 스레드를 가지며, 스레드는 프로세스의 자원을 공유한다. 스레드는 일졸의 실행 흐름이다. 단일 코어 CPU에서도 스레드를 전환해가며 수행하면서 멀티스레드처럼 보이게 된다. 하지만 스레드를 전환 하는 컨텍스트 스위칭(Context Switching)은 비용이 많이 든다. 하지만 Go에서는 CPU 코어마다 OS 스레드를 하나만 할당하기에 컨텍스트 스위칭 비용이 발생하지 않는다.

고루틴

모든 프로그램은 고루틴을 가지고 있다. main 함수는 고루틴이다. 고루틴은 go 키워드를 사용하여 실행한다. 호출된 함수는 새로운 고루틴에서 실행된다. 여러 고루틴을 사용하는 코드는 다음과 같다.
1package main 2 3package main 4 5import ( 6 "fmt" 7 "time" 8) 9 10func PrintHangul() { 11 haguls := []rune{'가', '나', '다', '라', '마', '바', '사'} 12 13 for _, h := range haguls { 14 time.Sleep(300 * time.Millisecond) 15 fmt.Printf("%c ", h) 16 } 17} 18 19func PrintNumbers() { 20 for i := 0; i <= 5; i++ { 21 time.Sleep(400 * time.Millisecond) 22 fmt.Printf("%d ", i) 23 } 24} 25 26func main() { 27 go PrintHangul() 28 go PrintNumbers() 29 30 time.Sleep(3 * time.Second) 31} 32 33// 출력 결과 34// 가 0 나 1 다 2 라 마 3 바 4 사 5 35
만약 서브 고루틴이 종료되지 않아도 메인 고루틴이 종료되면 프로그램이 종료된다.

서브 고루틴 기다리기

sync 패키지의 WaitGroup을 사용하여 서브 고루틴이 모두 종료될 때까지 기다릴 수 있다.
1package main 2 3import ( 4 "fmt" 5 "sync" 6) 7 8var wg sync.WaitGroup 9 10func SumAtoB(a, b int) { 11 sum := 0 12 for i := a; i <= b; i++ { 13 sum += i 14 } 15 fmt.Printf("%d부터 %d까지 합계는 %d입니다.\n", a, b, sum) 16 wg.Done() // 작업이 끝나면 작업 개수를 1 감소시킴 17} 18 19 20func main() { 21 wg.Add(10) // 작업 개수 설정 22 23 for i := 0; i < 10; i++ { 24 go SumAtoB(1, 1000000000) 25 } 26 27 wg.Wait() // 모든 작업이 끝날 때까지 대기 28} 29

뮤텍스

뮤텍스는 공유 자원에 대한 접근을 제어하는 기법이다. 뮤텍스는 sync 패키지의 Mutex를 사용한다.
1package main 2 3