-
코루틴(Coroutine) 기초프로그래밍/Kotlin 2024. 1. 29. 16:22
코루틴을 사용하기 전 의존성을 추가해야한다.
dendendcies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3") testImplementation(kotlin("test)) }
runBlocking
- 코루틴을 생성하는 코루틴 빌더.
- runBlocking으로 감싼 코드는 코루틴 내부의 코드가 수행이 끝날 때까지 스레드가 블록킹된다.
fun main() { runBlocking { println("hello") println(Thread.currentThread().name) } println("world") println(Thread.currentThread().name) } // Hello // main @coroutine#1 // world // main // 둘다 main thread 이지만 코루틴 블럭에서 실행된 코드는 스레드에 coroutine 수식어가 붙어있다. // 이를 확인하려면 - d 를 누른 후 kotlinx coroutines debug 옵션을 넣자. // runBlocking 실행이 끝나야 다음 코드가 읽힌다. // 잘 쓰이지 않는다.
launch
- 스레드 차단 없이 새 코루틴을 시작하고 결과로 잡이라 하는 결과를 반환하는 코루틴 빌더
- 실행에 대한 흐름 조절 가능
- 단, 비동기 처리에 대한 결과를 가져오는것은 불가
fun main() = runBlocking<Unit> { launch { delay(500) // 코루틴 라이브러리에서 정의된 일시중단. 스레드를 블록킹하지 않음. // Thread.sleep(500) 스레드를 블록킹 함 println("world") } println("hello") } // hello // world
fun main() = runBlocking<Unit> { val job1: Job = launch { val elapsedTime = measureTimeMillis { delay(150) } println("async task-1 $elapsedTime ms") } job1.cancel() val job2: Job = launch { val elapsedTime = measureTimeMillis { delay(100) } println("async task-2 $elapsedTime ms") } val job3: Job = launch(start=CoroutineStart.LAZY) { val elapsedTime = measureTimeMillis { delay(100) } println("async task-3 $elapsedTime ms") } println("start task-3") job3.start() }
async builder
- 비동기 작업을 통해서 결과를 만들어 낼 때 사용
- 비동기 처리를 할 때 async 함수를 사용하고 결과를 받아올 때는 await 을 사용해주면 된다.
- 병렬 처리도 가능하다
- 반환 타입은 Deffered<T> 로 되어 있으며, Deffered 내부에는 결과를 받아올 수 있는 await을 제공하고 있다.
fun sum(a: Intm b:Int) = a + b fun main() = runBlocking<Unit> { val result1: Deffered<Int> = async { delay(100) sum(1,3) } println("result1 : ${result1.await()}") val result2 = async { delay(100) sum(2,5) } println("result2 : ${result2.await()}") }
suspend
- 코루틴의 핵심 요소로 일시 중단이 가능한 함수를 말한다.
- suspend 함수는 일반 함수를 마음껏 호출할 수 있지만 일반 함수에선 suspend 함수를 일반적으로는 바로 호출 불가능
- 호출을 위해 runblocking 을 사용하던지, 호출함수가 suspend 가 되어야 한다.
- suspend 함수에서 async, launch 와 같은 코루틴 빌더를 사용하려면 coroutineScope를 사용해야 한다.
- coroutineScope 와 runblocking 의 다른점은 coroutineScope 은 현재 스레드가 차단되지 않는다 (논블록킹)
suspend fun main() { doSomething() } fun printHello() = println("hello") suspend fun doSomething() = coroutineScope { laynch { delay(200) println("world") } laynch { printHello() } }
flow
- 코루틴에서 리액티브 프로그래밍 스타일로 작성할 수 있도록 만들어진 API
- suspend 함수의 경우 reactor Mono 처럼 단일 값을 비동기로 반환하지만 flow을 사용하게되면 reactor Flux 처럼 여러 개의 값을 반환할 수 있다.
- flow 도 리액티브 스타일처럼 최종 연산자인 collect 를 호출해 줘야만 이 코드가 동작한다.
fun main() = runBlocking<Unit> { val flow = simple() flow.collect{ value -> println(value) } } fun simpel(): Flow<Int> = flow { println("flow started") for(i in 1..3) { delay(100) emit(i) // 데이터 통지 } }