Skip to content

코루틴 기본 및 구조화된 동시성 학습 내용 정리 및 테스트 코드 추가#27

Merged
sh1mj1 merged 14 commits intodevfrom
kotlin/coroutine/basic
May 26, 2025
Merged

코루틴 기본 및 구조화된 동시성 학습 내용 정리 및 테스트 코드 추가#27
sh1mj1 merged 14 commits intodevfrom
kotlin/coroutine/basic

Conversation

@sh1mj1
Copy link
Owner

@sh1mj1 sh1mj1 commented May 25, 2025

코틀린 코루틴의 기본적인 개념과 핵심 기능, 그리고 구조화된 동시성에 대한 학습 내용을 정리하고, 이를 검증하기 위한 단위 테스트 코드를 추가했습니다.

주요 학습 및 구현 내용:

  • 코루틴 빌더: launch, runBlocking, async의 사용법과 특징을 학습하고 테스트했습니다.
    • Job 객체를 이용한 코루틴 제어 (시작, 취소, 상태 확인, 완료 대기 - join, joinAll, cancelAndJoin)
    • Deferredawait, awaitAll을 사용한 결과 처리
    • CoroutineStart.LAZY를 이용한 지연 시작 코루틴
    • withContext를 사용한 컨텍스트 전환 및 순차/병렬 실행 시의 주의점
  • 코루틴 상태: 코루틴의 생명주기(New, Active, Completing, Cancelling, Cancelled, Completed)와 각 상태에 따른 isActive, isCancelled, isCompleted 플래그 변화를 테스트로 확인했습니다.
  • CoroutineContext: CoroutineDispatcher, CoroutineName, Job, CoroutineExceptionHandler 등 주요 구성 요소와 조합 방식을 학습하고, 컨텍스트 요소 접근 및 변경을 테스트했습니다.
  • 구조화된 동시성 (Structured Concurrency):
    • 부모-자식 코루틴 관계 및 실행 환경(컨텍스트) 상속
    • 부모 코루틴의 자식 코루틴 완료 대기 (Completing 상태)
    • 부모 코루틴 취소 시 자식 코루틴으로의 전파
    • Job 객체를 통한 코루틴 계층 구조화
  • CoroutineScope: 코루틴의 실행 범위 제어, 스코프를 통한 코루틴 일괄 취소, isActive 상태 확인 등을 학습하고 테스트했습니다.
  • 학습 내용 문서화: study-coroutine.md 파일에 코루틴의 주요 개념과 학습한 내용을 체계적으로 정리했습니다.

주요 변경 사항

  • 테스트 코드 추가:
    • CoroutineBuilderJobTest.kt: launch 빌더와 Job 객체 관련 테스트
    • CoroutineBasicStateTest.kt: 코루틴의 다양한 상태 변화 테스트
    • CoroutineBuilderAsyncTest.kt: async, Deferred, await, withContext 관련 테스트
    • CoroutineContextTest.kt: CoroutineContext의 구성 및 사용법 테스트
    • StructuredConcurrencyTest.kt: 구조화된 동시성, 부모-자식 코루틴 관계, 컨텍스트 상속 테스트
    • CoroutineScopeTest.kt: CoroutineScope 동작 방식 테스트
  • 학습 문서 추가/수정:
    • study-coroutine.md: 코루틴 기본 개념부터 구조화된 동시성까지 학습 내용 상세 정리
  • 유틸리티 추가:
    • TestFixture.kt: 테스트 시 시간 측정을 위한 유틸리티 함수 추가

sh1mj1 added 14 commits May 23, 2025 17:41
- launch 빌더로 시작된 코루틴(Job) 간의 의존 관계를 관리하여 원하는 순서대로 작업을 실행 테스트

- join() 함수를 사용하여 특정 Job이 완료될 때까지 현재 코루틴을 일시 중단시켜 순차 실행 보장

- joinAll() 함수를 사용하여 여러 Job이 모두 완료될 때까지 현재 코루틴을 일시 중단시켜 다음 작업의 실행 순서를 보장
- Job.cancel() 은 코루틴을 중단시킨다
- 양보 지점(delay, yield 또는 isActive 확인과 같은)이 없는 무한 루프는 취소할 수 없다
- 양보 지점을 추가하면 코루틴이 협력적이 되어 취소 가능해진다
- cancel 호출 직후에도 Job이 즉시 취소 완료되지 않아 이후 코드가 먼저 실행될 수 있다
- Job.cancelAndJoin()을 사용하여 취소 완료 후 순차적인 실행을 보장하는 테스트 케이스 추가
- 해당 테스트에서 cancelAndJoin() 호출 후 추가된 로그만 남는 것을 확인
- 즉시 시작되는 launch 코루틴은 launch 호출과 동시에 실행된다
- CoroutineStart.LAZY 옵션을 사용하면 코루틴이 생성되어도 start()를 호출하기 전까지 실행되지 않는다
- elapsedTimeMilli 헬퍼 함수를 추가
- 코루틴의 5가지 상태(생성, 실행 중, 실행 완료, 취소 중, 취소 완료)에 대한 테스트 케이스
- async 빌더는 Job의 하위 타입인 Deferred를 리턴한다.
- Deferred의 await() 함수를 호출하여 결과를 받을 수 있다.
- await() 호출 시 코루틴은 결과 반환까지 일시 중단된다.
- awaitAll()을 사용하여 여러 Deferred의 결과를 한 번에 기다릴 수 있다.
- withContext는 새 코루틴을 만들지 않고 CoroutineContext만 변경한다.
  - 이를 통해 스레드 전환이 가능하다.
  - 작업 완료 후 이전 실행 환경으로 복귀한다.
  - 병렬 실행이 필요한 경우 async를 사용해야 한다.
- CoroutineContext는 CoroutineName, CoroutineDispatcher, Job, CoroutineExceptionHandler 등의 구성 요소를 가진다.
- '+' 연산자로 CoroutineContext에 구성 요소를 추가할 수 있으며, 동일한 키의 요소가 추가되면 나중 값으로 덮어쓴다.
- 키를 사용하여 CoroutineContext의 요소에 접근할 수 있다.
- CoroutineName, CoroutineDispatcher, Job, CoroutineExceptionHandler는 모두 CoroutineContext를 상속한다.
- EmptyCoroutineContext는 어떠한 구성 요소도 가지지 않는다.
- 각 구성 요소는 고유한 Key를 가지며, 이를 통해 구분된다.
- minusKey 함수를 사용하여 CoroutineContext에서 특정 구성 요소를 제거할 수 있다.
- 부모 코루틴의 CoroutineContext(CoroutineName, CoroutineDispatcher)는 자식 코루틴에 상속된다.
- 자식 코루틴에 새로운 CoroutineContext가 전달되면, 부모의 해당 Context 요소는 덮어씌워진다.
- 코루틴 빌더 함수(launch 등)는 호출 시마다 새로운 Job 객체를 생성한다.
- 자식 코루틴 Job은 parent 프로퍼티로 부모 Job을, 부모 코루틴 Job은 children 프로퍼티로 자식 Job들을 참조하여 양방향 관계를 가진다.
… 부모-자식 코루틴 관계 테스트

- CoroutineBasicStateTest:
    - 부모 코루틴의 모든 코드가 실행되었지만, 자식 코루틴이 아직 실행 중인 경우 부모 코루틴은 '실행 완료 중' 상태가 된다.
    - 이 상태에서 부모 코루틴의 isActive는 true, isCancelled는 false, isCompleted는 false이다.
- StructuredConcurrencyTest:
    - 부모 코루틴에 취소 요청이 발생하면 자식 코루틴으로 전파되어 자식 코루틴도 취소된다.
    - 부모 코루틴은 모든 자식 코루틴이 완료될 때까지 기다렸다가 완료된다.
    - 이를 확인하기 위해 각 코루틴의 실행 완료 시간을 비교한다
- CoroutineScope는 코루틴 빌더에게 실행 환경을 제공한다.
- `CoroutineScope()` 생성자 함수를 사용하여 코루틴 스코프를 만들 수 있다.
- 스코프 내 launch는 스코프의 Job을 부모로 가진다.
- 새로운 CoroutineScope를 생성하여 부모 스코프로부터 독립적인 코루틴을 실행할 수 있다 (권장하지 않음).
- CoroutineScope의 `cancel()`은 해당 스코프 내 모든 코루틴을 취소한다.
- `CustomCoroutineScope` 예시를 통해 CoroutineContext를 직접 정의하는 방법을 보여준다.
- CoroutineScope를 새로 생성하거나 launch 시 새로운 Job 객체를 전달하여 구조화된 동시성을 벗어날 수 있으며, 이 경우 부모 Job이 완료되어도 자식 코루틴은 완료되지 않는다.
- Job을 사용하여 특정 코루틴만 취소되지 않도록 제어할 수 있다.
- 생성된 Job에 명시적으로 부모 Job을 설정하여 구조화된 동시성을 유지할 수 있지만, 이 경우 Job의 완료를 수동으로 처리해야 한다.
코루틴의 부모-자식 관계, `Job` 객체의 역할, `CoroutineScope`를 이용한 실행 범위 제어 등 구조화된 동시성에 대한 내용을 추가합니다.
- 스레드 기반 작업의 한계와 코루틴의 등장 이유를 설명한다.
- `CoroutineDispatcher`의 종류, 역할, 사용법 및 주요 디스패처(`Default`, `IO`, `Main`)를 설명한다.
- `launch`, `Job` 등 코루틴 빌더와 `Job` 객체의 상태 및 제어 방법을 설명한다.
    - `join`, `joinAll`, `cancel`, `cancelAndJoin`
    - 코루틴 상태 (New, Active, Completing, Cancelling, Cancelled, Completed)와 `Job` 프로퍼티 (`isActive`, `isCancelled`, `isCompleted`)의 관계를 표로 정리한다.
@sh1mj1 sh1mj1 merged commit a8e6baf into dev May 26, 2025
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant