프로그래밍/Kotlin

코루틴(Coroutine) 기초

개발정리 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) // 데이터 통지
    }
}