Goroutines와 채널을 통한 Go에서 동시성 마스터링
Min-jun Kim
Dev Intern · Leapcell

Key Takeaways
- Goroutines는 Go에서 효율적인 동시 실행을 가능하게 하는 경량 스레드입니다.
- 채널은 고루틴 간의 안전한 통신 및 동기화를 용이하게 합니다.
- 작업자 풀 및 파이프라인과 같은 패턴은 동시성을 효과적으로 구조화하고 관리하는 데 도움이 됩니다.
Go(종종 Golang이라고 함)는 효율적이고 확장 가능한 애플리케이션 개발을 위한 강력한 도구로서 내장된 동시성 지원으로 유명합니다. Go의 동시성 모델의 중심에는 여러 작업을 동시에 실행하고 이들 간의 통신을 가능하게 하는 고루틴과 채널이 있습니다.
Goroutines: 경량 스레드
고루틴은 Go 런타임에 의해 관리되는 경량 스레드입니다. 기존 스레드와 달리 고루틴은 메모리 효율성이 더 높고 더 적은 수의 OS 스레드에 다중화되어 상당한 오버헤드 없이 수천 개의 동시 작업을 생성할 수 있습니다.
고루틴을 시작하려면 함수 호출 앞에 go
키워드를 붙이기만 하면 됩니다.
package main import ( "fmt" "time" ) func sayHello() { fmt.Println("Hello from goroutine") } func main() { go sayHello() time.Sleep(1 * time.Second) // 고루틴이 실행될 시간을 줍니다. fmt.Println("Main function finished") }
이 예제에서 sayHello
는 main
함수와 동시에 실행됩니다. time.Sleep
은 고루틴이 실행을 완료하기 전에 프로그램이 종료되지 않도록 합니다.
채널: 고루틴 간 통신
Go의 채널은 고루틴이 통신하고 실행을 동기화하는 방법을 제공합니다. 이는 채널 연산자 <-
를 사용하여 값을 보내고 받을 수 있는 유형화된 도관입니다.
채널 생성 및 사용
채널을 생성하고 사용하는 방법은 다음과 같습니다.
package main import "fmt" func main() { messages := make(chan string) go func() { messages <- "Hello, Channel!" }() msg := <-messages fmt.Println(msg) }
이 코드에서:
make(chan string)
은string
유형의 새 채널을 생성합니다.- 익명 고루틴은 채널에 메시지를 보냅니다.
- main 함수는 채널에서 메시지를 받아 출력합니다.
버퍼링된 채널 vs. 버퍼링되지 않은 채널
-
버퍼링되지 않은 채널: 이러한 채널은 다른 고루틴이 채널에서 값을 받을 때까지 보내는 고루틴을 차단합니다. 이는 동기화에 유용합니다.
-
버퍼링된 채널: 이러한 채널에는 용량이 있으며 해당 수신 없이 제한된 수의 값을 보낼 수 있습니다. 이는 보내는 사람과 받는 사람 간의 타이밍을 분리하려는 경우에 유용합니다.
버퍼링된 채널의 예:
package main import "fmt" func main() { messages := make(chan string, 2) messages <- "Buffered" messages <- "Channel" fmt.Println(<-messages) fmt.Println(<-messages) }
Go의 동시성 패턴
Go의 동시성 모델은 다양한 동시성 패턴 구현을 가능하게 합니다. 다음은 몇 가지 일반적인 패턴입니다.
작업자 풀 패턴
작업자 풀 패턴은 공유 채널에서 작업을 처리하는 고정된 수의 고루틴(작업자)을 생성하는 것과 관련됩니다. 이 패턴은 동시성 수준을 제어하고 시스템 리소스를 효율적으로 활용하는 데 유용합니다.
package main import ( "fmt" "sync" ) func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) { defer wg.Done() for j := range jobs { fmt.Printf("Worker %d processing job %d\n", id, j) results <- j * 2 } } func main() { const numJobs = 5 jobs := make(chan int, numJobs) results := make(chan int, numJobs) var wg sync.WaitGroup for w := 1; w <= 3; w++ { wg.Add(1) go worker(w, jobs, results, &wg) } for j := 1; j <= numJobs; j++ { jobs <- j } close(jobs) wg.Wait() close(results) for r := range results { fmt.Println("Result:", r) } }
이 예에서:
- 세 명의 작업자가 5개의 작업을 처리합니다.
sync.WaitGroup
은 main 함수가 진행하기 전에 모든 작업자가 완료될 때까지 기다리도록 합니다.
파이프라인 패턴
파이프라인 패턴은 각 단계가 입력 채널을 받아 출력 채널을 반환하는 함수인 일련의 단계를 연결하는 것과 관련됩니다. 이 패턴은 여러 단계를 통해 데이터를 동시에 처리하는 데 유용합니다.
package main import "fmt" func gen(nums ...int) <-chan int { out := make(chan int) go func() { for _, n := range nums { out <- n } close(out) }() return out } func sq(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { out <- n * n } close(out) }() return out } func main() { c := gen(2, 3, 4) out := sq(c) for n := range out { fmt.Println(n) } }
이 파이프라인에서:
gen
은 숫자를 생성하고 채널로 보냅니다.sq
는 채널에서 숫자를 읽고 제곱하여 결과를 다른 채널로 보냅니다.
Go의 동시성을 위한 모범 사례
-
경쟁 조건 방지: 채널 또는
sync.Mutex
와 같은 동기화 기본 요소를 사용하여 공유 변수에 대한 동시 액세스를 방지합니다. -
고루틴 제한: 제어되지 않은 고루틴 스폰은 리소스 고갈로 이어질 수 있습니다. 작업자 풀 또는 세마포어를 사용하여 동시성을 제한합니다.
-
정상 종료: 컨텍스트 취소 또는 닫는 채널을 사용하여 고루틴에 중지 신호를 보냅니다.
-
오류 처리: 오류를 정상적으로 처리하고 main 함수 또는 오류 처리 루틴으로 다시 전달하도록 고루틴을 설계합니다.
결론
고루틴과 채널을 중심으로 하는 Go의 동시성 모델은 동시 애플리케이션 구축을 위한 강력한 프레임워크를 제공합니다. 이러한 구성 요소를 활용하고 확립된 동시성 패턴을 따르면 개발자는 최신 멀티 코어 프로세서를 완전히 활용하는 효율적이고 확장 가능하며 유지 관리 가능한 코드를 작성할 수 있습니다.
자세한 내용과 실제 예제는 다음 리소스를 참조하세요.
FAQs
버퍼링되지 않은 채널은 수신될 때까지 차단하는 반면, 버퍼링된 채널은 제한된 비동기 보내기를 허용합니다.
고루틴은 Go 런타임에서 관리되며 더 가볍고 수천 개가 동시에 실행될 수 있습니다.
컨텍스트 취소를 사용하거나 채널을 닫아 고루틴에 정상 종료 신호를 보냅니다.
저희 Leapcell은 Go 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하세요.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 비용을 지불하고 요청이나 요금은 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불합니다.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 지표 및 로깅.
간편한 확장성 및 고성능
- 고도의 동시성을 쉽게 처리할 수 있도록 자동 확장됩니다.
- 운영 오버헤드가 없으므로 구축에만 집중하세요.
설명서에서 자세히 알아보세요!
X에서 팔로우하세요: @LeapcellHQ