반응형
Coroutine
Coroutine이란?
- 코루틴은 비동기 프로그래밍을 위한 도구로서, 코드를 비동기적으로 실행할 수 있도록 도와주는 라이브러리를 말한다.
- 코루틴은 기본적으로 경량 스레드와 비슷한 동작을 하지만, 스레드보다 적은 리소스를 소비하고 더 효율적으로 관리될 수 있다
스레드로 여러 작업 처리
- 동시에 여러 작업이 필요할 때 각 작업별로 스레드를 생성하여 각각의 스레드 위에서 처리하도록 할 수 있다.
- A 스레드의 작업 도중 B 스레드로 컨텍스트 스위칭이 중간에 발생할 수 있다
- 컨텍스트 스위칭 과정은 무겁고, 리소스 사용권이 B 스레드에게 넘어갈 경우 A 스레드는 작업을 진행하지 못하여 리소스를 낭비하는 경우가 생긴다.
코루틴으로 여러 작업 처리
- 코루틴은 각 작업별로 코루틴을 생성하여 처리하도록 한다.
- 각 코루틴은 최소한으로 생성된 스레드 풀 위에서 동작한다.
- 컨텍스트 스위칭 과정이 최소화 되기 때문에 성능상 이점이 있다.
의존성
dependencies {
// ...
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
}
Coroutine Scope
Coroutine Scope란?
- 코루틴이 실행되는 범위를 말한다.
GlobalScope
- 애플리케이션이 실행될 때 생성하여 사용하는 스코프(Singleton)
- 메모리 누수의 원인이 될 수 있기 때문에 신중히 사용해야한다.
GlobalScope.launch {
// task
}
CoroutineScope
- 필요할 때 생성하여 사용하는 스코프
CoroutineScope(Dispatchers.IO).launch {
// task
}
Coroutine Builder
Coroutine Builder란?
- 코루틴을 시작하는 방법을 제공하는 함수를 말한다.
launch
- 작업을 시작하고 결과를 반환하지 않는 함수
GlobalScope.launch {
// task
}
async
- 작업을 시작하고 결과를 Deffered 타입으로 반환하는 함수
val deferred = GlobalScope.async {
"결과값"
}
val result = deferred.await() // 계산이 끝날 때까지 기다린 후 값 가져오기
runBlocking
- 호출한 스레드를 블록킹하면서 코루틴을 실행하고 결과를 반환하는 함수
- 일반적으로 사용하지 않고 주로 테스트나 메인 함수에서 사용된다.
runBlocking {
// task
}
withContext
- 이미 실행 중인 코루틴 내부에서 컨텍스트를 변경하는데 사용하는 함수.
코드
GlobalScope.launch(newFixedThreadPoolContext(1, "mainThread")) {
println("[${Thread.currentThread().name}] start")
val result = withContext(Dispatchers.IO) {
delay(1000)
println("[${Thread.currentThread().name}] io")
"Hello World"
}
println("[${Thread.currentThread().name}] result - $result")
}
출력
[mainThread] start
[DefaultDispatcher-worker-1] io
[mainThread] result - Hello World
withTimeout
try {
withTimeout(1000L) { // timeout 시간을 밀리초 단위로 설정 (여기서는 1초)
repeat(1000) { i ->
println("Some work $i ...")
delay(500L)
}
}
} catch (e: TimeoutCancellationException) {
println("Timed out with exception: ${e.message}")
}
withTimeoutOrNull
val result = withTimeoutOrNull(1000L) { // timeout 시간을 밀리초 단위로 설정 (여기서는 1초)
repeat(1000) { i ->
println("Some work $i ...")
delay(500L)
}
"Done" // 정상적으로 완료됐을 때 반환되는 값
}
println("Result is $result")
Coroutine Context
Coroutine Context란?
- 코루틴의 동작과 상태를 결정하는 속성.
- 코루틴 컨텍스트에서 가장 중요한 두 가지 요소는 Job과 Dispatcher이다.
- Job: 코루틴의 생명주기를 관리
- Dispatcher: 코루틴이 어느 스레드에서 실행될지 결정
GlobalScope.launch(Dispatchers.Default + CoroutineName("testCoroutine")) { // 컨텍스트에 디스패처와 이름을 추가
println("[${Thread.currentThread().name}] coroutineName: ${coroutineContext[CoroutineName]?.name}, isActive: ${coroutineContext.isActive}")
}
val job = GlobalScope.launch {
delay(1000)
println("job")
}
job.cancel() // job 종료 가능
val threadLocal = ThreadLocal<String>()
threadLocal.set("Hello")
println("[${Thread.currentThread().name}] main start - ${threadLocal.get()}") // Hello
GlobalScope.launch(Dispatchers.Default + threadLocal.asContextElement(value = "World")) {
println("[${Thread.currentThread().name}] coroutine - ${threadLocal.get()}") // World
}
println("[${Thread.currentThread().name}] main end - ${threadLocal.get()}") // Hello
Coroutine Dispatcher
Coroutine Dispatcher란?
- 코루틴이 어느 스레드에서 실행될지 결정하는 역할.
- 컨텍스트의 종류 중 하나.
Dispatchers.Default
- 동시 작업 가능한 최대 갯수는 CPU의 코어 수와 같다.
- 대기시간이 없고 지속적으로 CPU 작업을 필요로하는 무거운 작업에 적합하다.(ex. 파싱 작업, 복잡한 연산 등)
CoroutineScope(Dispatchers.Default).launch {
// task
}
Dispatchers.IO
- 필요에 따라 추가적으로 스레드를 더 생성하여 동시 작업이 가능하다.(최대 64개까지 생성 가능)
- 대기시간이 긴 작업을 필요로하는 무거운 작업에 적합하다.(ex. 네트워크 통신, 파일 입출력 등)
CoroutineScope(Dispatchers.IO).launch {
// task
}
newFixedThreadPoolContext
- 사용자가 원하는 스레드의 수를 지정함으로써 동시에 실행할 코루틴의 최대 수를 제한할 수 있다.
예제 코드
// val dispatcher = Executors.newFixedThreadPool(2).asCoroutineDispatcher()
val dispatcher = newFixedThreadPoolContext(2, "myDispatcher")
repeat(5) {
CoroutineScope(dispatcher).launch {
println("[${Thread.currentThread().name}] Hello World")
}
}
// 사용이 끝났을 때, 스레드 풀을 반드시 종료
dispatcher.close()
출력
[myDispatcher-1] Hello World
[myDispatcher-2] Hello World
[myDispatcher-1] Hello World
[myDispatcher-2] Hello World
[myDispatcher-1] Hello World
참고 링크
반응형
'Development > Kotlin' 카테고리의 다른 글
[Kotlin] Jackson (0) | 2024.12.31 |
---|---|
[Kotlin] Kotlin 소스 파일 컴파일하여 Class 객체로 로딩하기 (0) | 2023.05.27 |
[Kotlin] 기본 문법 (0) | 2020.12.28 |