Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4주차 키워드 학습! #13

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions week_4/김동건.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# 4주차

- 다음의 키워드에 대해 학습을 진행 (실습 포함)
- continuation, Dispatchers, async, launch, suspend, coroutineScope, coroutineContext, yield, runBlocking, withContext

<br>
<br>
<hr>
<br>
<br>


### suspend

- suspend 함수는 **일시 중지(suspension)**가 가능한 함수로, 이를 호출한 코루틴은 특정 지점에서 중단되고, 결과가 준비되면 다시 실행
- 비동기 작업을 처리할 수 있는 특수한 함수를 정의할 때 사용
- suspend 함수는 **일시 중지(suspension)**가 가능하며, 이를 통해 동기적인 코드처럼 보이지만 비동기적으로 실행되는 기능을 제공
- suspend 함수가 호출되면, 그 함수 내부에서 **일시 중지(suspension)**를 할 수 있는 시점에 코루틴이 중단
- 그런 다음, 비동기 작업이 완료되면 코루틴이 다시 실행

**Reactor와의 가장 큰 차이점**

> 일반적인 비동기 방식에서는 Callback이나 Promise를 사용하지만, suspend 함수는 콜백 지옥을 피하고 동기적인 코드 스타일로 비동기 작업을 처리할 수 있습니다.


<br>
<br>
<hr>
<br>
<br>

### yield

> yield는 코루틴이 자발적으로 일시 중지할 수 있는 지점을 만드는 데 사용됩니다. 코루틴의 일시 중지 지점을 명시적으로 만들고, 다른 코루틴이 실행될 수 있도록 하여 스케줄링을 제공합니다.

**yield와 코루틴의 동작**

- yield는 코루틴을 일시 중지하고, 코루틴이 다시 실행되도록 요청하는 함수
- 주로 코루틴의 협력적 스케줄링을 제어하는 데 사용
- yield를 호출하면, 해당 코루틴은 일시 중지되고 다른 대기 중인 코루틴이 실행될 수 있게 함.
- 이 방식은 동시성을 관리하는 방법으로 사용되며, 주로 CPU 바운드 작업에서 실행을 "양보"할 때 유용

**yield() 내부 구현**

실제로 yield는 Kotlin 코루틴 라이브러리에서 어떻게 구현될까요? Kotlin의 코루틴은 협력적 스케줄링을 지원하는데, 이때 코루틴은 일시 중지 지점을 설정하고, 이를 관리하는 스케줄러가 존재합니다.

suspend 함수 내부에서 yield가 호출되면, 현재 실행 중인 코루틴은 중단되고, 다음 코루틴이 실행될 수 있게 스케줄링됩니다. 이때 중요한 것은 yield가 자발적으로 코루틴을 일시 중지하는 함수라는 점입니다.

**yield의 내부적인 흐름**

- yield()가 호출되면 현재 실행 중인 코루틴은 일시 중지되고, 해당 코루틴의 상태는 Continuation 객체에 저장
- 다른 대기 중인 코루틴이 재개되어 실행될 수 있음.
- 만약, 일시 중지된 코루틴이 다시 실행되면, Continuation을 통해 다시 실행
- 이 과정은 Kotlin 코루틴의 내부 스케줄러가 관리하고, 실제로는 코루틴의 상태 관리, 재개, 스케줄링 등을 담당

**yield의 성능 측면**

- yield는 협력적 스케줄링을 제공하므로, CPU 바운드 작업에서는 리소스를 효율적으로 분배
- 하지만, 과도하게 yield를 사용하는 것은 오히려 성능에 부담을 줄 수 있음.
- yield가 자주 호출되면, 그만큼 코루틴 간 전환 비용이 발생할 수 있기 때문

<br>
<br>
<hr>
<br>
<br>

### continuation

- 코루틴이 일시 중지된 지점과 상태를 추적하고, 해당 코루틴을 다시 실행할 수 있도록 관리하는 객체
- 코루틴이 일시 중지되는 시점에서 중단된 상태와 그 시점의 정보(상태, 인자, 로컬 변수 등)를 추적하고, 이후 다시 실행할 수 있게 관리하는 객체가 바로 Continuation

**주요 역할**

- 일시 중지된 상태 추적
- 코루틴이 일시 중지되는 시점에서, 그 코루틴이 수행 중이던 작업에 대한 상태를 저장.
- 이 상태 정보는 나중에 코루틴을 재개하는 데 필요.
- 코루틴 재개
- 코루틴이 중단된 후, Continuation은 코루틴을 다시 실행(재개)할 수 있도록 관리이때, 일시 중지된 위치에서 작업이 재개되며, 코루틴이 다시 실행
- 결과 반환: Continuation은 코루틴이 실행을 마친 후 결과를 반환하는 책임 존재.
- 코루틴의 종료 후, 해당 결과를 처리하는 데 사용

**continutation의 주요 속성**
- context
- 코루틴의 실행 컨텍스트(디스패처, 직렬화 등) 정보를 담고 있는 CoroutineContext 객체
- resumeWith(result: Result<T>)
- 코루틴을 재개하는 메서드
- resumeWith는 코루틴을 재개할 때 사용되며, result에는 코루틴의 실행 결과
- 성공적인 실행 결과는 Result.success(value)로 감싸지며, 예외가 발생하면 Result.failure(exception)으로 감쌈.

<br>
<br>
<hr>
<br>
<br>


### coroutineScope

- coroutineScope는 코루틴 빌더의 일종으로, 새로운 **코루틴 범위(scope)**를 생성하고 그 범위 내에서 실행되는 모든 코루틴이 완료될 때까지 기다림.
- coroutineScope 내에서 예외가 발생하면, 예외가 상위 코루틴으로 전파되지 않도록 처리함.
- coroutineScope는 코루틴을 효율적으로 관리하고, 예외를 안전하게 처리하는 역할
- 새로운 코루틴 범위를 만들고, 해당 범위 내에서 실행되는 모든 코루틴이 완료될 때까지 기다리며, 예외가 발생해도 외부 코루틴으로 예외가 전파되지 않도록 안전하게 처리

<br>
<br>
<hr>
<br>
<br>

### coroutineContext

- 코루틴의 환경을 정의하고 관리하는 객체로, 코루틴의 디스패처(Dispatcher), Job, 예외 처리기, 제어 흐름 등을 설정하는 데 사용
- 코루틴의 실행 환경을 나타내며, 이를 통해 코루틴이 어떤 스레드에서 실행될지, 코루틴의 취소 및 예외 처리 방법을 지정

**개념 deep dive**

- coroutineContext는 코루틴의 실행 환경을 정의하는 Context 객체로, 여러 개의 **Element**가 결합된 집합체
- coroutineContext는 코루틴이 실행되는 동안 필요한 디스패처, Job, 예외 처리기 등을 제공하고, 코루틴이 시작될 때와 종료될 때, 그리고 중간에 상태가 변경될 때 이러한 요소들이 조합되어 실행
- coroutineContext는 코루틴의 실행 환경을 나타내는 속성으로, 코루틴이 실행되는 동안 사용할 수 있는 컨텍스트 요소들의 집합을 제공

**Job**

- Job은 코루틴의 상태와 관련된 정보를 담고 있는 객체
- Job은 코루틴이 시작되고, 완료되며, 취소될 수 있는지 여부를 추적
- Job을 통해 코루틴의 취소, 예외 처리와 같은 동작을 관리
- Job을 사용하여 코루틴을 취소하거나, 다른 코루틴의 완료 여부를 기다릴 수 있음
- Job은 코루틴의 계층 구조에서 부모-자식 관계를 관리

<br>
<br>
<hr>
<br>
<br>

### runBlocking

- 호출하는 현재 스레드를 차단(Blocking) 하면서 코루틴을 실행하는 함수
- 주로 main 함수나 테스트 환경에서 사용하며, runBlocking 블록 내부에서 비동기 작업을 동기적으로 실행
- runBlocking은 새로운 코루틴 스코프(CoroutineScope) 를 생성
- 이 코루틴 스코프 내에서 실행되는 모든 코루틴이 완료될 때까지 현재 스레드를 차단
- 내부적으로는 Dispatcher.Main 또는 Dispatcher.Default 대신 BlockingEventLoop를 사용해 작업을 처리
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runBlocking 을 호출한 스레드를 EventLoop 의 메인 스레드로 잡는거군요,

- runBlocking은 호출 스레드를 차단하므로, 웹 서버나 프로덕션 환경에서 사용하면 스레드 리소스가 비효율적으로 사용
- runBlocking은 스레드를 차단하므로, 많은 요청을 처리해야 하는 환경에서는 스레드 풀 부족 또는 응답 지연을 초래

**주요 특징**
- 현재 스레드 차단
- runBlocking을 호출하면 현재 스레드가 블로킹 상태에 들어가며, 내부의 모든 작업이 끝날 때까지 해당 스레드는 다른 작업을 수행하지 못함.
- 이는 suspend 함수처럼 비차단(Non-blocking) 방식과 대조
- 동기적 테스트
- 주로 코루틴 기반 코드를 테스트할 때, 비동기 로직을 동기적으로 실행하며 결과를 확인할 수 있는 환경을 제공
- 프로덕션 코드에서의 제한
- 서버 애플리케이션이나 프로덕션 코드에서는 블로킹 작업이 성능 병목을 초래할 수 있으므로, 사용을 피하는 것이 좋음.

<br>
<br>
<hr>
<br>
<br>

### Dispatchers

> 틀린 코루틴에서 코루틴이 실행될 스레드 또는 스레드 풀을 결정하는 구성 요소


- 코루틴 빌더(launch, async)에서 디스패처를 명시하지 않으면 기본 디스패처가 사용
- Dispatchers.Default: GlobalScope 또는 최상위 코루틴.
- 부모의 디스패처: 부모 코루틴이 있을 경우 이를 상속.

**기본 개념**

- 스레드 관리: Dispatchers는 코루틴이 실행될 스레드 또는 스레드 풀을 관리.
- 스레드 컨텍스트: 코루틴의 실행 컨텍스트를 정의.
- 비동기 처리 최적화: 작업 유형에 따라 적합한 스레드 풀을 선택하여 효율적인 실행 보장.

**Dispatchers.Default**

- 정의: CPU-집약적인 작업에 최적화된 디스패처.
- 스레드 풀: Runtime.getRuntime().availableProcessors()에 기반한 고정 크기 스레드 풀을 사용.
- 적합한 작업
- 대규모 데이터 처리
- 복잡한 계산 작업 (ex. 알고리즘 실행)
- 백그라운드 처리
- 특징
- 작업이 많아지면 스레드 풀 크기가 제한적이므로 스케줄링에 따라 지연이 발생할 수 있음.

**Dispatchers.IO**

- 정의: I/O-집약적인 작업에 최적화된 디스패처.
- 스레드 풀: 기본적으로 최대 64개의 스레드까지 확장 가능.
- 적합한 작업:
- 파일 읽기/쓰기
- 네트워크 통신 (ex. HTTP 요청)
- 데이터베이스 쿼리 처리
- 특징
- 차단 작업을 효율적으로 처리.
- 스레드 풀 크기가 커서 많은 I/O 작업을 병렬적으로 실행 가능.

**Dispatchers.Main**

- 정의: UI 작업에 최적화된 디스패처.
- 스레드: 메인 스레드(UI 스레드)에서 실행.
- 적합한 작업:
- UI 업데이트 (ex. 안드로이드, 자바FX, Swing 등에서 사용)
- 짧고 가벼운 작업
- 특징
- UI 스레드에서 실행되므로 작업 시간이 길어지면 앱 응답성이 저하될 수 있음.
- UI 프레임워크(Android, JavaFX 등)에 따라 추가 의존성을 설정해야 함. (ex. kotlinx-coroutines-android)

**Dispatchers.Unconfined**

- 정의: 스레드를 고정하지 않고, 호출된 컨텍스트에서 코루틴을 시작.
- 스레드 이동
- 초기에는 호출한 스레드에서 실행되지만, 첫 번째 suspend 함수 이후에는 재개 시점의 스레드에서 실행.
- 특징
- 테스트 또는 매우 가벼운 작업에 적합.
- 비권장: 스레드 이동이 예상치 못한 결과를 초래할 수 있어, 프로덕션 코드에서는 사용하지 않는 것이 좋음.

<br>
<br>
<hr>
<br>
<br>

### withContext

- withContext는 호출 시 현재 코루틴 컨텍스트를 일시 중단하고, 새 컨텍스트에서 작업을 실행.
- 작업이 완료되면 결과를 반환하고 원래 컨텍스트로 복귀.
- 코루틴 내부에서 withContext는 비동기로 실행되지만, 호출자는 결과를 기다릴 때까지 일시 중단.

**기본개념**

- 컨텍스트 전환: 코루틴 실행 중 다른 CoroutineContext로 전환.
- suspend 함수: withContext는 suspend 함수로, 호출 시 현재 작업을 일시 중단(suspend)하고, 지정된 디스패처에서 작업을 수행.
- 비동기→동기: 특정 컨텍스트에서 동기식으로 코드를 실행하고, 완료 시 원래 컨텍스트로 복귀.

**주요특징**
- 컨텍스트 변경: 실행 중인 코루틴의 디스패처(스레드 풀) 또는 기타 컨텍스트 요소를 동적으로 변경.
- 비차단(Non-blocking): 호출한 코루틴을 차단하지 않음. 내부적으로 비동기 작업으로 처리.
- 디스패처 최적화: CPU-집약적 작업, I/O 작업, UI 업데이트 등 작업 유형에 적합한 디스패처를 선택해 성능 최적화.
- 자원 효율성: 작업이 완료되면 자동으로 컨텍스트가 해제됨. 리소스 관리를 명시적으로 할 필요 없음.


### async, launch

| **특징** | **`launch`** | **`async`** |
| ------------- | ------------------------------------------ | ------------------------------------- |
| **반환값** | `Job` (작업 핸들링용 객체) | `Deferred<T>` (결과를 반환하는 객체) |
| **작업 방식** | **결과를 기다리지 않음** (fire-and-forget) | **결과를 반환** (값을 기다릴 수 있음) |
| **사용 목적** | 작업 실행 및 완료 감시 | 작업 실행 및 **결과값 처리** |

**`launch`**

- **정의**: 코루틴을 실행하지만 **결과를 반환하지 않는** 코루틴 빌더.
- **반환값**: 작업을 제어할 수 있는 **`Job` 객체**를 반환.
- **특징**:
- "결과"가 필요 없는 비동기 작업에 적합.
- 작업 실패 시 예외가 바로 전달되지 않고, **부모 코루틴에 전파**됨.
- 주로 `runBlocking`이나 `GlobalScope` 내부에서 사용.


**`async`**

- **정의**: 코루틴을 실행하며, 결과값을 반환하는 코루틴 빌더.
- **반환값**: **`Deferred<T>`** 객체를 반환.
- **`Deferred`**는 비동기적으로 계산된 결과를 나타내는 객체로, **`await()`**를 호출해 결과를 기다림.
- **특징**:
- "결과"가 필요한 비동기 작업에 적합.
- 작업 실패 시 예외가 `await()` 호출 시점에 전달됨.