Learning
레슨 3 / 8·20분

고루틴과 채널

고루틴 (goroutine)

고루틴은 Go의 경량 스레드입니다. go 키워드를 함수 호출 앞에 붙이면 새로운 고루틴에서 동시에 실행됩니다. OS 스레드보다 훨씬 가벼워서 수만 개를 동시에 실행할 수 있습니다.

go
package main

import (
    "fmt"
    "time"
)

func sayHello(name string) {
    for i := 0; i < 3; i++ {
        fmt.Printf("[%s] %d번째 인사\n", name, i+1)
        time.Sleep(100 * time.Millisecond)
    }
}

func main() {
    go sayHello("고루틴A")  // 고루틴으로 실행
    go sayHello("고루틴B")  // 또 다른 고루틴

    // 메인이 끝나면 고루틴도 종료됨
    time.Sleep(500 * time.Millisecond)
}

채널 (chan)과 select

채널(chan)은 고루틴 간에 안전하게 데이터를 주고받는 통로입니다. <- 연산자로 데이터를 보내고 받습니다. select는 여러 채널을 동시에 대기할 때 사용합니다.

go
package main

import "fmt"

func sum(numbers []int, ch chan int) {
    total := 0
    for _, n := range numbers {
        total += n
    }
    ch <- total  // 채널에 결과 보내기
}

func main() {
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
    ch := make(chan int)

    // 반씩 나눠서 동시에 합산
    go sum(numbers[:4], ch)
    go sum(numbers[4:], ch)

    x, y := <-ch, <-ch  // 채널에서 결과 받기
    fmt.Println(x, y, x+y)  // 10 26 36 (순서는 변할 수 있음)
}
go
package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(100 * time.Millisecond)
        ch1 <- "one"
    }()
    go func() {
        time.Sleep(200 * time.Millisecond)
        ch2 <- "two"
    }()

    // select — 먼저 도착한 채널의 값을 처리
    for i := 0; i < 2; i++ {
        select {
        case msg := <-ch1:
            fmt.Println("ch1:", msg)
        case msg := <-ch2:
            fmt.Println("ch2:", msg)
        }
    }
}
  • go func() — 새 고루틴에서 함수 실행
  • ch := make(chan T) — 타입 T의 채널 생성
  • ch <- value — 채널에 값 보내기
  • value := <-ch — 채널에서 값 받기 (블로킹)
  • select — 여러 채널 중 준비된 것을 처리
  • sync.WaitGroup — 여러 고루틴의 완료를 대기
💡

채널을 닫지 않고 고루틴이 끝나면 메모리 누수가 발생할 수 있습니다. defer close(ch)로 채널을 닫는 습관을 들이세요.