context를 공부하는 이유
git hub에서 Go를 사용하는 잘 짜여진 프로젝트들은 context를 잘 사용한다. 프로젝트에 엮인 micro service가 많아지면 많아질수록 더 효율적인 스킬처럼 느껴지며 context를 사용하는 부분을 미리 익혀두면 도움이 될 듯 하다.
context란?
context. 사전적 뜻은 “문맥”이다. 그리고 문맥의 정의는
프로세스 진행 중, 프로세스의 앞 뒤 간 맥락이라 표현할 수 있겠다.
Go에서 사용되는 context 또한 크게 다르지 않다. Context는 작업 명세서와 같은 역할로 프로젝트의 앞뒤 흐름을 관찰하고 제어할 수 있게 도와준다.
context를 사용하는 이유
context는 다음 작업의 매개변수로 보낼 context를 위해 자식 context를 생성한다. 생성된 자식 context는 다음 작업의 매개변수로 보내지는 식으로 파생되며 트리 형태로 관리된다. 만일 한 context의 Cancel() 함수가 호출되면 그 함수가 가진 Done 채널이 닫히고 그 context의 자식 context를 가진 작업들의 진행을 중단시킬 수 있다.
간단한 예시를 들어보자.
A는 OO 뱅크의 애플리케이션에서 최근 10년간의 이체 목록 데이터를 요청했다. 하지만 시간이 너무 오래 걸려 A는 애플리케이션을 종료해버렸다. OO 뱅크의 서버는 이 요청자료를 DB에서 조회하여 가져오고 이 데이터들을 열심히 가공하고 있다. 하지만 A는 이미 애플리케이션을 종료한 지 오래다. 서버는 괜히 본인의 서버 자원을 소모한 것이다.
이런 경우에 context를 사용한다면 A가 애플리케이션을 종료 했을 때 서버의 작업을 중단시킬 수 있다.
즉, context는 프로젝트의 진행을 제어하는 역할을 할 수 있다.
context 구조
context는 Context interface와 이를 구현한 구현체인 emptyCtx, cancelCtx를 가진다.
// Context의 Interface
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}
// Context Interface의 구현체
type emptyCtx int
// Context Interface의 구현체
type cancelCtx struct {
Context
mu sync.Mutex
done atomic.Value
children map[canceler]struct{}
err error
}
go의 context package에 직접 들어가 보면 주석을 통한 자세한 설명과 사용 예시 및 테스트 코드를 볼 수 있다.
Context 별 사용 목적 및 방법
앞에서 context는 두 가지 구현체가 구현돼 있는 것을 보였다. 이 구현체를 사용한 context들의 목적과 사용 방법을 살펴보겠다.
emptyCtx
생성
ctxBackground := context.Background()
ctxTODO := context.TODO()
사용 목적 및 방법
Background(), TODO() 함수가 반환하는 값의 타입은 같다. 즉, 같은 행동을 할 수 있는 값을 반환한다.
하지만 이들은 흐름을 제어할 수 있는 능력이 없다. Context interface를 구현한 함수 들도 오직 nil 값을 반환한다. 하지만 두 함수의 사용 목적에는 차이가 있다.
- Background()
- 주로 main 함수나 init 함수와 같은 최상의 요청을 받는 곳에서 사용된다.
- TODO()
- Context의 목적이 명확하지 못할 경우 사용한다.
❗️Context를 매개변수로 받는 함수에게 Context 값을 nil로 보내는 것은 안된다. 이와 같은 경우에 context.TODO()를 사용하자
cancelCtx
생성
ctxWithCancel, cancel := context.WithCancel(context.Background())
ctxWithDeadline, cancel := context.WithDeadline(context.Background(), TIME)
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), TIME)
사용 목적 및 방법
emptyCtx와 달리 cancel이라는 값을 반환받는 것을 볼 수 있다. 이 cancel이라는 것은 함수이다. 1급 함수를 가지는 go 이기에 cancel 변수에 함수를 받을 수 있다.
cancel에 담기는 함수는 cancelCtx 구조체가 가지는 children map[canceler]struct{} 에 저장된 자식 context들을 모두 취소하는 역할을 한다.
기본적 사용 방법은 모두 같다. 하지만 함수 이름에서 볼 수 있듯 각자의 목적이 다르다.
- WithCancel()
- cancel이 호출될 시
- WithDeadline
- cancel이 호출될 시
- 작업을 마치지 못하고 입력한 TIME이 됐을 시
- WithTimeout
- cancel이 호출될 시
- 작업을 마치지 못하고 입력한 TIME의 시간이 지났을 시
참조
'Study > Go' 카테고리의 다른 글
[Go] Google OAuth2.0 적용 (0) | 2022.08.29 |
---|---|
[Go] GC(Garbage Collection) 심화 (0) | 2022.08.05 |
[Go] 고루틴(GoRoutine) 심화(7) - 파이프라인 (0) | 2022.06.24 |
[Go] 고루틴(GoRoutine) 심화(6) - 고루틴 에러 처리 (0) | 2022.06.20 |
[Go] 고루틴(GoRoutine) 심화(5) - 누수 관리 (0) | 2022.05.24 |