Go 언어에서 Context 없이 Multi Job 처리하기

Golang

Go 언어는 병렬 처리를 간단하고 강력하게 구현할 수 있도록 goroutine과 채널이라는 도구를 제공합니다. 일반적으로 여러 작업을 동시에 처리하고 중간에 중단하거나 타임아웃을 주고 싶을 때는 context를 사용하는 것이 권장되지만, 모든 상황에서 꼭 필요한 것은 아닙니다.

이번 글에서는 context 없이도 goroutine과 채널만으로 여러 개의 작업(Multi Job)을 효율적으로 실행하고 제어하는 방법을 소개하겠습니다. 특히 가볍고 단순한 구조를 원하는 경우에 매우 유용한 패턴입니다.


왜 context 없이 처리하려 할까?

Go의 context는 취소 신호 전파, 타임아웃 관리 등에 유용하지만, 다음과 같은 경우에는 오히려 불필요하게 느껴질 수 있습니다:

  • 프로그램 구조가 단순하고 복잡한 취소 체계가 필요하지 않은 경우
  • 고루틴 종료를 WaitGroup과 채널로 충분히 제어할 수 있는 경우
  • 외부 패키지나 함수가 context를 요구하지 않는 경우

이럴 땐 오히려 context 없이 코드를 구성하는 것이 더 깔끔하고 직관적입니다.


핵심 구성 요소

구성 요소역할
goroutine각 작업을 병렬로 실행
sync.WaitGroup모든 작업이 끝날 때까지 기다림
chan struct{}(선택) 종료 또는 신호 전달용

실전 예제: context 없이 5개의 작업 동시에 처리하기

package main

import (
"fmt"
"sync"
"time"
)

func main() {
var wg sync.WaitGroup
jobCount := 5

fmt.Println("여러 작업을 동시에 실행합니다.")

for i := 1; i <= jobCount; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
runJob(id)
}(i)
}

// 모든 작업이 끝날 때까지 대기
wg.Wait()
fmt.Println("모든 작업이 완료되었습니다.")
}

func runJob(id int) {
fmt.Printf("작업 #%d 시작\n", id)
for i := 0; i < 3; i++ {
fmt.Printf("작업 #%d 진행 중... (%d/3)\n", id, i+1)
time.Sleep(1 * time.Second)
}
fmt.Printf("작업 #%d 완료\n", id)
}

결과 예시

여러 작업을 동시에 실행합니다.
작업 #1 시작
작업 #2 시작
작업 #3 시작
작업 #4 시작
작업 #5 시작
작업 #3 진행 중... (1/3)
작업 #1 진행 중... (1/3)
작업 #4 진행 중... (1/3)
...
모든 작업이 완료되었습니다.

중간에 취소하고 싶다면? (간단한 종료 시그널 추가)

context 없이도 고루틴에 종료 신호를 보내고 싶다면 공통 채널을 닫는 방식으로 구현할 수 있습니다

stop := make(chan struct{})

각 goroutine 내부에서:

select {
case <-stop:
fmt.Printf("작업 #%d 중단됨\n", id)
return
default:
// 계속 진행
}

그리고 특정 조건(예: 오류 발생)에서 close(stop)을 호출하면 모든 고루틴이 이를 감지하고 종료할 수 있습니다.


장점과 단점

✅ 장점

  • context 없이도 goroutine을 안전하게 병렬 실행
  • 간단한 구조에서 직관적인 코드
  • 외부 종속성 없이 표준 패키지만으로 구현 가능

❌ 단점

  • goroutine이 많아질수록 종료 제어가 복잡해짐
  • 취소 전파와 타임아웃 같은 고급 기능은 직접 구현해야 함
  • 외부 API 호출, 데이터베이스 트랜잭션에는 적합하지 않음

실무 팁

  • context를 도입하기 전에 먼저 이 구조로 작은 프로그램을 설계해보세요.
  • 단일 책임 goroutine을 만든 후, 채널을 통해 입력/출력을 제어하면 더 유연한 구조가 됩니다.
  • 클라이언트가 취소 요청을 보낼 수 없는 환경 (예: 로컬 스크립트 실행)에서는 굳이 context를 쓰지 않아도 됩니다.

마무리

Go 언어는 병렬 처리에 강력한 도구들을 제공합니다. 꼭 context를 써야만 여러 작업을 제어할 수 있는 건 아닙니다. 때로는 단순한 goroutine + WaitGroup 조합이 가장 명확하고 효율적인 선택이 될 수 있습니다.

작고 단순한 프로그램일수록, 꼭 필요한 기능만 구현하고 의존성을 줄이는 것이 코드 유지 관리에 큰 도움이 됩니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤