From 326f610a4b6ad4fff60cc52198b5cadc8c50f769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B7=B9=EB=9D=BD=EC=BD=94=EB=94=A9?= <50691225+DongGeon0908@users.noreply.github.com> Date: Tue, 26 Nov 2024 23:13:08 +0900 Subject: [PATCH] =?UTF-8?q?Create=20=EA=B9=80=EB=8F=99=EA=B1=B4.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\352\271\200\353\217\231\352\261\264.md" | 270 ++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 "week_4/\352\271\200\353\217\231\352\261\264.md" diff --git "a/week_4/\352\271\200\353\217\231\352\261\264.md" "b/week_4/\352\271\200\353\217\231\352\261\264.md" new file mode 100644 index 0000000..e09c5be --- /dev/null +++ "b/week_4/\352\271\200\353\217\231\352\261\264.md" @@ -0,0 +1,270 @@ +# 4주차 + +- 다음의 키워드에 대해 학습을 진행 (실습 포함) +- continuation, Dispatchers, async, launch, suspend, coroutineScope, coroutineContext, yield, runBlocking, withContext + +
+
+
+
+
+ + +### suspend + +- suspend 함수는 **일시 중지(suspension)**가 가능한 함수로, 이를 호출한 코루틴은 특정 지점에서 중단되고, 결과가 준비되면 다시 실행 +- 비동기 작업을 처리할 수 있는 특수한 함수를 정의할 때 사용 +- suspend 함수는 **일시 중지(suspension)**가 가능하며, 이를 통해 동기적인 코드처럼 보이지만 비동기적으로 실행되는 기능을 제공 +- suspend 함수가 호출되면, 그 함수 내부에서 **일시 중지(suspension)**를 할 수 있는 시점에 코루틴이 중단 + - 그런 다음, 비동기 작업이 완료되면 코루틴이 다시 실행 + +**Reactor와의 가장 큰 차이점** + +> 일반적인 비동기 방식에서는 Callback이나 Promise를 사용하지만, suspend 함수는 콜백 지옥을 피하고 동기적인 코드 스타일로 비동기 작업을 처리할 수 있습니다. + + +
+
+
+
+
+ +### yield + +> yield는 코루틴이 자발적으로 일시 중지할 수 있는 지점을 만드는 데 사용됩니다. 코루틴의 일시 중지 지점을 명시적으로 만들고, 다른 코루틴이 실행될 수 있도록 하여 스케줄링을 제공합니다. + +**yield와 코루틴의 동작** + +- yield는 코루틴을 일시 중지하고, 코루틴이 다시 실행되도록 요청하는 함수 +- 주로 코루틴의 협력적 스케줄링을 제어하는 데 사용 +- yield를 호출하면, 해당 코루틴은 일시 중지되고 다른 대기 중인 코루틴이 실행될 수 있게 함. +- 이 방식은 동시성을 관리하는 방법으로 사용되며, 주로 CPU 바운드 작업에서 실행을 "양보"할 때 유용 + +**yield() 내부 구현** + +실제로 yield는 Kotlin 코루틴 라이브러리에서 어떻게 구현될까요? Kotlin의 코루틴은 협력적 스케줄링을 지원하는데, 이때 코루틴은 일시 중지 지점을 설정하고, 이를 관리하는 스케줄러가 존재합니다. + +suspend 함수 내부에서 yield가 호출되면, 현재 실행 중인 코루틴은 중단되고, 다음 코루틴이 실행될 수 있게 스케줄링됩니다. 이때 중요한 것은 yield가 자발적으로 코루틴을 일시 중지하는 함수라는 점입니다. + +**yield의 내부적인 흐름** + +- yield()가 호출되면 현재 실행 중인 코루틴은 일시 중지되고, 해당 코루틴의 상태는 Continuation 객체에 저장 +- 다른 대기 중인 코루틴이 재개되어 실행될 수 있음. +- 만약, 일시 중지된 코루틴이 다시 실행되면, Continuation을 통해 다시 실행 +- 이 과정은 Kotlin 코루틴의 내부 스케줄러가 관리하고, 실제로는 코루틴의 상태 관리, 재개, 스케줄링 등을 담당 + +**yield의 성능 측면** + +- yield는 협력적 스케줄링을 제공하므로, CPU 바운드 작업에서는 리소스를 효율적으로 분배 +- 하지만, 과도하게 yield를 사용하는 것은 오히려 성능에 부담을 줄 수 있음. +- yield가 자주 호출되면, 그만큼 코루틴 간 전환 비용이 발생할 수 있기 때문 + +
+
+
+
+
+ +### continuation + +- 코루틴이 일시 중지된 지점과 상태를 추적하고, 해당 코루틴을 다시 실행할 수 있도록 관리하는 객체 +- 코루틴이 일시 중지되는 시점에서 중단된 상태와 그 시점의 정보(상태, 인자, 로컬 변수 등)를 추적하고, 이후 다시 실행할 수 있게 관리하는 객체가 바로 Continuation + +**주요 역할** + +- 일시 중지된 상태 추적 + - 코루틴이 일시 중지되는 시점에서, 그 코루틴이 수행 중이던 작업에 대한 상태를 저장. + - 이 상태 정보는 나중에 코루틴을 재개하는 데 필요. +- 코루틴 재개 + - 코루틴이 중단된 후, Continuation은 코루틴을 다시 실행(재개)할 수 있도록 관리이때, 일시 중지된 위치에서 작업이 재개되며, 코루틴이 다시 실행 +- 결과 반환: Continuation은 코루틴이 실행을 마친 후 결과를 반환하는 책임 존재. + - 코루틴의 종료 후, 해당 결과를 처리하는 데 사용 + +**continutation의 주요 속성** +- context + - 코루틴의 실행 컨텍스트(디스패처, 직렬화 등) 정보를 담고 있는 CoroutineContext 객체 +- resumeWith(result: Result) + - 코루틴을 재개하는 메서드 + - resumeWith는 코루틴을 재개할 때 사용되며, result에는 코루틴의 실행 결과 + - 성공적인 실행 결과는 Result.success(value)로 감싸지며, 예외가 발생하면 Result.failure(exception)으로 감쌈. + +
+
+
+
+
+ + +### coroutineScope + +- coroutineScope는 코루틴 빌더의 일종으로, 새로운 **코루틴 범위(scope)**를 생성하고 그 범위 내에서 실행되는 모든 코루틴이 완료될 때까지 기다림. +- coroutineScope 내에서 예외가 발생하면, 예외가 상위 코루틴으로 전파되지 않도록 처리함. +- coroutineScope는 코루틴을 효율적으로 관리하고, 예외를 안전하게 처리하는 역할 +- 새로운 코루틴 범위를 만들고, 해당 범위 내에서 실행되는 모든 코루틴이 완료될 때까지 기다리며, 예외가 발생해도 외부 코루틴으로 예외가 전파되지 않도록 안전하게 처리 + +
+
+
+
+
+ +### coroutineContext + +- 코루틴의 환경을 정의하고 관리하는 객체로, 코루틴의 디스패처(Dispatcher), Job, 예외 처리기, 제어 흐름 등을 설정하는 데 사용 +- 코루틴의 실행 환경을 나타내며, 이를 통해 코루틴이 어떤 스레드에서 실행될지, 코루틴의 취소 및 예외 처리 방법을 지정 + +**개념 deep dive** + +- coroutineContext는 코루틴의 실행 환경을 정의하는 Context 객체로, 여러 개의 **Element**가 결합된 집합체 +- coroutineContext는 코루틴이 실행되는 동안 필요한 디스패처, Job, 예외 처리기 등을 제공하고, 코루틴이 시작될 때와 종료될 때, 그리고 중간에 상태가 변경될 때 이러한 요소들이 조합되어 실행 +- coroutineContext는 코루틴의 실행 환경을 나타내는 속성으로, 코루틴이 실행되는 동안 사용할 수 있는 컨텍스트 요소들의 집합을 제공 + +**Job** + +- Job은 코루틴의 상태와 관련된 정보를 담고 있는 객체 +- Job은 코루틴이 시작되고, 완료되며, 취소될 수 있는지 여부를 추적 +- Job을 통해 코루틴의 취소, 예외 처리와 같은 동작을 관리 + - Job을 사용하여 코루틴을 취소하거나, 다른 코루틴의 완료 여부를 기다릴 수 있음 + - Job은 코루틴의 계층 구조에서 부모-자식 관계를 관리 + +
+
+
+
+
+ +### runBlocking + +- 호출하는 현재 스레드를 차단(Blocking) 하면서 코루틴을 실행하는 함수 +- 주로 main 함수나 테스트 환경에서 사용하며, runBlocking 블록 내부에서 비동기 작업을 동기적으로 실행 +- runBlocking은 새로운 코루틴 스코프(CoroutineScope) 를 생성 +- 이 코루틴 스코프 내에서 실행되는 모든 코루틴이 완료될 때까지 현재 스레드를 차단 +- 내부적으로는 Dispatcher.Main 또는 Dispatcher.Default 대신 BlockingEventLoop를 사용해 작업을 처리 +- runBlocking은 호출 스레드를 차단하므로, 웹 서버나 프로덕션 환경에서 사용하면 스레드 리소스가 비효율적으로 사용 +- runBlocking은 스레드를 차단하므로, 많은 요청을 처리해야 하는 환경에서는 스레드 풀 부족 또는 응답 지연을 초래 + +**주요 특징** +- 현재 스레드 차단 + - runBlocking을 호출하면 현재 스레드가 블로킹 상태에 들어가며, 내부의 모든 작업이 끝날 때까지 해당 스레드는 다른 작업을 수행하지 못함. + - 이는 suspend 함수처럼 비차단(Non-blocking) 방식과 대조 +- 동기적 테스트 + - 주로 코루틴 기반 코드를 테스트할 때, 비동기 로직을 동기적으로 실행하며 결과를 확인할 수 있는 환경을 제공 +- 프로덕션 코드에서의 제한 + - 서버 애플리케이션이나 프로덕션 코드에서는 블로킹 작업이 성능 병목을 초래할 수 있으므로, 사용을 피하는 것이 좋음. + +
+
+
+
+
+ +### 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 함수 이후에는 재개 시점의 스레드에서 실행. +- 특징 + - 테스트 또는 매우 가벼운 작업에 적합. + - 비권장: 스레드 이동이 예상치 못한 결과를 초래할 수 있어, 프로덕션 코드에서는 사용하지 않는 것이 좋음. + +
+
+
+
+
+ +### withContext + +- withContext는 호출 시 현재 코루틴 컨텍스트를 일시 중단하고, 새 컨텍스트에서 작업을 실행. +- 작업이 완료되면 결과를 반환하고 원래 컨텍스트로 복귀. +- 코루틴 내부에서 withContext는 비동기로 실행되지만, 호출자는 결과를 기다릴 때까지 일시 중단. + +**기본개념** + +- 컨텍스트 전환: 코루틴 실행 중 다른 CoroutineContext로 전환. +- suspend 함수: withContext는 suspend 함수로, 호출 시 현재 작업을 일시 중단(suspend)하고, 지정된 디스패처에서 작업을 수행. +- 비동기→동기: 특정 컨텍스트에서 동기식으로 코드를 실행하고, 완료 시 원래 컨텍스트로 복귀. + +**주요특징** +- 컨텍스트 변경: 실행 중인 코루틴의 디스패처(스레드 풀) 또는 기타 컨텍스트 요소를 동적으로 변경. +- 비차단(Non-blocking): 호출한 코루틴을 차단하지 않음. 내부적으로 비동기 작업으로 처리. +- 디스패처 최적화: CPU-집약적 작업, I/O 작업, UI 업데이트 등 작업 유형에 적합한 디스패처를 선택해 성능 최적화. +- 자원 효율성: 작업이 완료되면 자동으로 컨텍스트가 해제됨. 리소스 관리를 명시적으로 할 필요 없음. + + +### async, launch + +| **특징** | **`launch`** | **`async`** | +| ------------- | ------------------------------------------ | ------------------------------------- | +| **반환값** | `Job` (작업 핸들링용 객체) | `Deferred` (결과를 반환하는 객체) | +| **작업 방식** | **결과를 기다리지 않음** (fire-and-forget) | **결과를 반환** (값을 기다릴 수 있음) | +| **사용 목적** | 작업 실행 및 완료 감시 | 작업 실행 및 **결과값 처리** | + +**`launch`** + +- **정의**: 코루틴을 실행하지만 **결과를 반환하지 않는** 코루틴 빌더. +- **반환값**: 작업을 제어할 수 있는 **`Job` 객체**를 반환. +- **특징**: + - "결과"가 필요 없는 비동기 작업에 적합. + - 작업 실패 시 예외가 바로 전달되지 않고, **부모 코루틴에 전파**됨. + - 주로 `runBlocking`이나 `GlobalScope` 내부에서 사용. + + +**`async`** + +- **정의**: 코루틴을 실행하며, 결과값을 반환하는 코루틴 빌더. +- **반환값**: **`Deferred`** 객체를 반환. + - **`Deferred`**는 비동기적으로 계산된 결과를 나타내는 객체로, **`await()`**를 호출해 결과를 기다림. +- **특징**: + - "결과"가 필요한 비동기 작업에 적합. + - 작업 실패 시 예외가 `await()` 호출 시점에 전달됨. +