Goroutine 개념 및 특징

shjk·2025년 5월 9일

Goroutine 정의

Goroutine은 Go 언어에서 지원하는 경량(lightweight)의 독립적인 실행 단위로, 병행성(concurrency)을 쉽게 구현할 수 있도록 설계된 메커니즘이다. 전통적인 스레드(thread)와 비교할 때, 적은 메모리 오버헤드와 높은 성능을 제공한다.


Goroutine의 특징

Goroutine의 주요한 특징은 다음과 같다.

1. 경량성 (Lightweight)

  • Goroutine은 운영체제의 네이티브 스레드보다 훨씬 적은 메모리 공간을 사용한다.
  • 일반적으로 하나의 Goroutine은 수 킬로바이트(KB)의 스택 공간만을 사용한다.
  • 수천, 수만 개의 Goroutine을 동시에 실행할 수 있다.

2. 비선점형 협력 스케줄링 (Non-preemptive Cooperative Scheduling)

  • Go 런타임은 비선점형 방식으로 Goroutine을 스케줄링하며, 협력적으로 작업을 교체한다.
  • Goroutine이 명시적으로 I/O 작업이나 채널 통신 등에서 블로킹될 때만 다른 Goroutine에게 제어권이 넘어간다.

3. M:N 스케줄링 모델

  • Goroutine은 M\:N 스케줄링 방식을 따른다. 여기서 M은 OS 스레드 개수, N은 Goroutine 개수를 의미한다.
  • Go 런타임 스케줄러는 여러 개의 Goroutine(N)을 적은 수의 OS 스레드(M)에 매핑해 실행한다.
  • 이를 통해 높은 병행성을 효율적으로 처리할 수 있다.

Goroutine 사용법

Goroutine은 간단히 함수 호출 앞에 go 키워드를 붙여 실행한다.

// 일반적인 함수 호출
myFunc()

// Goroutine을 통한 비동기 호출
go myFunc()

예제는 다음과 같다.

package main

import (
    "fmt"
    "time"
)

func printMessage(msg string) {
    for i := 0; i < 3; i++ {
        fmt.Println(msg, ":", i)
        time.Sleep(time.Millisecond * 500)
    }
}

func main() {
    go printMessage("goroutine") // Goroutine 생성
    printMessage("main")         // 메인 함수 실행
}

위 코드 실행 결과는 다음과 같다.

main : 0
goroutine : 0
main : 1
goroutine : 1
main : 2
goroutine : 2

위와 같이 Goroutine이 동시에 병행하여 실행된다.


Goroutine 동기화 (Synchronization)

병행 실행 중 Goroutine 간 데이터 경쟁(Race Condition)을 방지하기 위해 동기화 메커니즘이 필요하다. 주로 다음 두 가지 방법이 사용된다.

1. 채널(Channel)

채널은 Goroutine 간 통신과 동기화를 지원하는 자료구조이다.

package main

import "fmt"

func worker(done chan bool) {
    fmt.Println("Working...")
    done <- true // 작업 완료 알림
}

func main() {
    done := make(chan bool)
    go worker(done)
    <-done // 작업 완료 대기
    fmt.Println("Done")
}

2. 뮤텍스(Mutex)

뮤텍스는 공유된 리소스에 접근할 때 상호 배제를 보장한다.

package main

import (
    "fmt"
    "sync"
)

var counter int
var mutex sync.Mutex

func increment() {
    mutex.Lock()
    counter++
    mutex.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            increment()
        }()
    }
    wg.Wait()
    fmt.Println("Counter:", counter)
}

Goroutine의 활용 사례

  • 웹 서버 요청 처리
  • 실시간 메시지 처리 (채팅 서버)
  • 데이터 스트리밍 및 파이프라인 처리
  • 백그라운드 태스크 수행 (예: 로그 수집, 메트릭 집계)

Goroutine의 주의사항

  • 무분별한 Goroutine 생성은 메모리 누수 및 과도한 리소스 사용을 초래할 수 있다.
  • 데이터 경쟁 조건(Race Condition)을 주의하고 적절한 동기화가 필수적이다.
  • 장시간 실행되는 Goroutine의 종료 처리를 명확하게 설계해야 한다.

결론

Goroutine은 Go 언어에서 병행성 프로그래밍을 효율적이고 간단하게 구현할 수 있도록 설계된 핵심 요소로, 낮은 비용으로 높은 성능을 발휘한다. 그러나 사용 시 데이터 경쟁 및 동기화 문제에 주의해야 하며, 이를 적절히 관리할 수 있는 기법을 함께 사용하는 것이 권장된다.

profile
백엔드 개발자

0개의 댓글