Go 동시성 개방: Go 루틴 심층 분석
9월 07, 2025
# Go
Min-jun Kim
Dev Intern · Leapcell

Go가 동시 시스템 구축에 강력한 언어로 명성을 얻고 있는 것은 근본적인 기본 요소인 고루틴에 크게 뿌리를 두고 있습니다. 단순한 유행어 이상으로, 고루틴은 개발자가 놀라울 정도로 쉽게 고도로 동시적이고 성능이 뛰어난 애플리케이션을 작성할 수 있도록 하는 핵심 설계 철학입니다. 이 글에서는 고루틴의 세계를 깊이 파고들어 고루틴이 무엇인지, 어떻게 작동하는지, 그리고 이를 효과적으로 생성하고 사용하는 방법을 설명합니다.
고루틴이란 무엇인가? 동시성을 위한 경량 챔피언
마음속으로 고루틴은 동일한 주소 공간 내에서 다른 고루틴과 동시적으로 실행되는 경량의 독립 실행 기능입니다. 이들을 Go 런타임에 의해 관리되는 협력적인 사용자 수준 스레드로 생각할 수 있습니다. 일반적으로 메가바이트의 스택 공간을 소비하고 값비싼 컨텍스트 전환을 포함하는 전통적인 운영 체제 스레드와 달리, 고루틴은 놀라울 정도로 미니멀합니다.
- 작은 스택 크기: 고루틴은 일반적으로 매우 적은 스택(몇 킬로바이트, 종종 2KB)으로 시작하며 필요에 따라 동적으로 성장하고 축소될 수 있습니다. 이를 통해 Go 프로그램은 단일 머신에서 초당 수천, 심지어 수십만 개의 고루틴을 동시에 실행할 수 있습니다.
- Go 런타임에 의해 관리됨: Go 런타임 스케줄러는 더 적은 수의 운영 체제 스레드에 고루틴을 다중화합니다. 이는 OS 스레드를 직접 예약할 필요가 없다는 것을 의미합니다. 대신, Go 런타임에 어떤 함수를 동시에 실행할지 알려주면 Go 런타임이 저수준 세부 정보를 효율적으로 처리합니다.
- 협력적 스케줄링: Go 스케줄러는 선점형(고루틴을 중단할 수 있음)이지만, 고루틴은 일반적으로 협력적으로 설계되었습니다. 가능하면 가능한 한 공유 메모리와 잠금에 의존하기보다는 Go의 내장 동시성 기본 요소인 채널을 사용하여 통신하고 동기화해야 합니다.
핵심은 고루틴이 OS 스레드보다 훨씬 낮은 오버헤드를 제공하여 시스템을 느리게 하지 않고 방대한 수의 동시 작업을 실행하는 것이 가능하다는 것입니다.
첫 번째 고루틴 만들기: go
키워드
Go에서 고루틴을 만드는 것은 놀라울 정도로 간단합니다. 함수 호출 앞에 go
키워드를 추가하기만 하면 됩니다. 이렇게 하면 Go 런타임에 해당 함수를 새 고루틴으로 동시에 실행하도록 지시됩니다.
기본 예제를 살펴보겠습니다.
package main import ( "fmt" "time" ) func sayHello(name string) { time.Sleep(100 * time.Millisecond) // 약간의 작업 시뮬레이션 fmt.Printf("Hello, %s!\n", name) } func main() { fmt.Println("Main goroutine started.") // sayHello를 새 고루틴으로 시작 go sayHello("Alice") // 다른 sayHello를 새 고루틴으로 시작 go sayHello("Bob") fmt.Println("Main goroutine continues...") // 메인 고루틴은 다른 고루틴이 완료될 때까지 기다려야 합니다. // 그렇지 않으면 프로그램이 완료되기 전에 종료됩니다. time.Sleep(200 * time.Millisecond) // 고루틴이 실행될 시간 제공 fmt.Println("Main goroutine finished.") }
이 코드를 실행하면 다음과 유사한 출력이 표시될 가능성이 높습니다.
Main goroutine started.
Main goroutine continues...
Hello, Alice!
Hello, Bob!
Main goroutine finished.
몇 가지 주목할 점:
sayHello
고루틴을 시작한 직후 `