레슨 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)로 채널을 닫는 습관을 들이세요.