보통 한 프로세스 안에서 여러 개의 일을 동시에 진행시키기 위해서는 멀티스레드를 사용합니다. 자바 쉽게 배우기 20 - 스레드에서도 스레드에 대해 다룬 적이 있죠.
❓ 프로세스란 무엇인가요?
- 일반적으로 실행 중인 프로그램을 의미하고, 작업(Job) 혹은 태스크(Task)라고 불리기도 합니다.
❓ 멀티스레드란 무엇인가요?
- 멀티스레드는 한 프로세스 안에서 여러 개의 일이 동시에 진행되는 것을 의미합니다.
코틀린으로 이러한 동시성 프로그래밍을 구현할 때는 스레드뿐만 아니라 코틀린에서 기본적으로 제공하는 코루틴을 활용할 수 있습니다.
코루틴은 멀티 스레드가 가지는 단점(디버깅, 예측의 어려움, 코드 복잡도 높음)을 극복할 수 있기에 자주 사용되는 방식입니다.
동기와 비동기
동기 : 작업을 순서대로 진행함
비동기 : 작업을 순서와 무관하게 진행함
Blocking과 NonBlocking
Blocking : 호출된 함수가 작업을 완료할 때까지 호출한 쪽의 실행을 멈추고 기다립니다.
Non-Blocking : 호출한 쪽은 작업의 완료를 기다리지 않고 다른 작업을 계속 수행할 수 있습니다.
비동기 프로그래밍이란?
일반적으로 비동기 프로그래밍은 비동기와 Non-Blocking 방식을 동시에 사용하는 것을 의미합니다. 여러 작업을 대기 없이 순서에 무관하게 동시에 실행시키는 방식으로 프로그래밍하는 것이죠.
코루틴의 특징
- 프로세스의 heap 메모리를 공유해서 사용합니다.
- 문맥 교환이 없고 최적화된 비동기함수를 사용합니다.
- 비선점적으로 작동합니다.
- 협력형 멀티태스킹 구현에 적합합니다.
- 경량: 코루틴을 실행 중인 스레드를 차단하지 않는 중단(suspend)를 지원하므로 단일 스레드에서 많은 코루틴을 실행할 수 있습니다. 중단(suspend)은 많은 동시 작업을 지원하면서도 차단보다 메모리를 절약합니다.
- 메모리 누수 감소: 코틀린 Scope를 사용하여 범위 내에서 작업을 실행하게 합니다. 외부 범위는 모든 하위 코루틴이 완료될 때까지 완료될 수 없습니다.
- 기본으로 제공되는 취소 지원: 실행 중인 코루틴 계층 구조를 통해 자동으로 취소가 전달됩니다.
- Jetpack 통합: 많은 Jetpack 라이브러리에 코루틴을 완전히 지원하는 확장 프로그램이 포함되어 있습니다. 일부 라이브러리는 구조화된 동시 실행에 사용할 수 있는 자체 CoroutineScope도 제공합니다.
코루틴 공식 문서
인텔리제이 코루틴 Library 추가
File > Project Structure > Libraries > + > From Maven
아래의 검색어를 입력하여 원하는 버전을 찾아 선택 후 OK를 클릭합니다.
org.jetbrains.kotlinx:kotlinx-coroutines-core:
코루틴 스코프 Coroutine Scope
코루틴 스코프는 코루틴의 범위를 지정하는 역할을 합니다. 코루틴 스코프에 따라 코루틴 수명이 제한되며, 코루틴 스코프 안에서 코루틴 기능을 사용할 수 있습니다.
또한, 코루틴 스코프는 구조화된 동시성을 제공합니다.
❓ 구조화된 동시성이란?
코루틴간의 부모-자식 관계와, 그 관계에 따른 종료 및 취소의 전파를 의미합니다.
- 자식 코루틴은 부모 코루틴으로부터 코루틴 콘텍스트를 물려받습니다.
- 부모 코루틴은 자식 코루틴이 완료될 때까지 대기합니다.
- 부모 코루틴이 취소되면 자식 코루틴에게도 취소가 전파 됩니다.
- 자식 코루틴에서 에러가 발생하면, 부모 코루틴에게도 에러가 전파되어 모든 코루틴이 취소됩니다.
Scope 종류
코틀린 코루틴에 정의되어 있는 Scope를 사용하거나 직접 Custom 한 Scope을 사용할 수 있습니다.
GlobalScope | 애플리케이션 전체에서 코루틴을 실행할 때 사용되며, 애플리케이션이 종료될 때까지 살아 있습니다. |
CoroutineScope | 개발자가 직접 정의할 수 있는 스코프입니다. 이를 통해 특정 컨텍스트에서 코루틴을 실행하고 관리할 수 있습니다. |
supervisorScope | CoroutineScope와 유사하지만, 자식 코루틴의 예외 처리가 독립적입니다. 자식 코루틴 중 하나에서 예외가 발생해도 다른 자식 코루틴에는 영향을 미치지 않습니다. |
lifecycleScope | LifecycleOwner(보통 Activity나 Fragment)와 연결된 코루틴 스코프입니다. |
viewModelScope | ViewModel과 연결된 코루틴 스코프입니다. |
코루틴 빌더
launch / runBlocking / async
runBlocking | launch | async | |
중단시 호출 Thread |
Blocking | Non-Blocking | Non-Blocking |
반환값 | Job 객체 | Deferred<T> 객체 | |
특징 | Coroutine Scope 밖에서도 호출 가능 main함수, 테스트 용도로만 사용 (권장되지 않는 코루틴 빌더) |
join()을 사용하면 launch로 생성된 코루틴 작업이 끝날때까지 메인 코루틴을 기다리게 할 수 있음 | 결괏값을 받기위해 await() 사용 작업들간의 의존관계가 있을 때 사용함 |
import kotlinx.coroutines.*
fun main() = runBlocking { // CoroutineScope
launch { // 새로운 코루틴을 백그라운드에서 실행함
delay(1000L) // 1초동안 넌블로킹 지연
println("World!")
}
val a = async {
delay(1000L)
return@async "A"
}
println("Hello") // 메인 코루틴이 이전 코루틴이 지연되는 동안 실행됨
println(a.await())
}
// Hello
// (1초후)
// World!
// A
❓ Job 객체란 무엇인가요?
- Job 객체는 작업의 상태를 저장하는 객체입니다. Job객체를 통해 코루틴의 상태를 확인할 수 있습니다.
❓ Deffered<T> 객체란 무엇인가요?
- Job 객체를 확장한 개념으로, 비동기 작업의 결과를 반환할 수 있는 코루틴 핸들러입니다.
launch / async 매개변수 start
코루틴 시작 방법을 설정하는 매개변수입니다.
DEFAULT | 즉시 시작 매개변수를 입력하지 않을 경우 DEFAULT로 설정 |
LAZY | 처음에는 중단된 상태이며 start()나 await()로 시작 |
ATOMIC | 최적화된 방법으로 시작 |
UNDISPATCHED | 분산 처리 방법으로 시작 |
suspend fun doWork1(): String {
delay(1000)
return "Work1"
}
suspend fun doWork2(): String {
delay(3000)
return "Work2"
}
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async { doWork1() }
val two = async { doWork2() }
println("${one.await() + "_" + two.await()}")
}
println("Completed in $time ms")
}
// Work1_Work2
// Completed in 3040 ms
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async(start = CoroutineStart.LAZY) { doWork1() }
val two = async(start = CoroutineStart.LAZY) { doWork2() }
println("${one.await() + "_" + two.await()}")
}
println("Completed in $time ms")
}
// Work1_Work2
// Completed in 4078 ms
suspend 함수 (지연 함수, 중단 함수)
코루틴 기능을 지원하는 함수는 선언부에 suspend 키워드가 붙습니다.
suspend 함수는 또 다른 suspend 함수나 코루틴 블록 안에서만 사용할 수 있습니다.
현재 코루틴을 중단시키고 함수 내 작업을 수행하기 때문에 지연 함수, 중단 함수라고 부릅니다.
예시 ) delay()
public suspend fun delay(timeMillis: kotlin.Long): kotlin.Unit { /* compiled code */ }
코루틴에 대해 가장 기본적인 개념들만 다뤄봤습니다. 코틀린 익히기는 이것으로 마칩니다. 👏 지금까지 읽어주셔서 감사합니다. 🙇♀️
'개발언어 > Kotlin : 코틀린' 카테고리의 다른 글
코틀린 익히기 13 - 입출력 (1) | 2023.10.09 |
---|---|
코틀린 익히기 12 - Scope Function (0) | 2023.10.06 |
코틀린 익히기 11 - 컬렉션 프레임워크 (1) | 2023.10.04 |
코틀린 익히기 10 - 배열 (0) | 2023.10.01 |
코틀린 익히기 9 - 변성 Variance (0) | 2023.09.30 |