728x90
runBlocking
fun main() {
runBlocking {// 코루틴을 생성하는 코루틴 빌더, 런블록킹 함수로 감싼 코드는 코루틴 내부에 코드가 끝날때 까지 해당 스레드를 블록킹한다.
//일반적인 코드(스프링 MVC, 스프링 배치)와 같은 코드를 실행시킬때 사용한다.
println("Hello ")
println("Thread : ${Thread.currentThread().name} ") //실행 옵션에 coroutine 옵션을 켜야지만 보인다.
}
println("World")
println(Thread.currentThread().name)
}

- runBlocking은 코루틴을 생성하는 코루틴 빌더이다.
- runBlocking으로 감싼 코드는 코루틴 내부의 코드가 수행이 끝날 때까지 스레드가 Blocking 된다.
- 실행 옵션에 -Dkotlinx.coroutines.debug를 붙여주어야 코루틴에서 수행되는 스레드 이름 뒤에 코루틴 이름이 붙는 걸 확인할 수 있다.
- 일반적으로 코루틴은 스레드를 차단하지 않고 사용해야 하므로 runBlocking을 사용하는 것은 좋지 않지만, 꼭 사용해야 하는 경우가 있다(코루틴을 지원하지 않는 경우 -> 테스트 코드, 스프링 배치, 스프링 MVC...)
launch
fun main() = runBlocking<Unit> {
/*
launch { //비동기 실행, job이라는 특별한 값 반호나
delay(500) //코루틴에서 제공하는 일시 중단 함수로, 스레드를 차단하지 않고 일시중지된다.
//Thread.sleep(500)
println("World")
}
println("Hello")
//launch를 비동기로 실행하고, hello를 출력한 뒤, 500MS 이후 World를 출력한다.
*/
val job1:Job = launch {//launch 를 여러개 써서 병렬적으로 동작시킬 수 있다
val elapsedTime = measureTimeMillis {
delay(150)
}
println("async task-1 $elapsedTime ms")
}
//job1.cancel() //job을 받아 해당 비동기 로직을 조절할 수 잇다
val job2:Job = launch(start = CoroutineStart.LAZY) { //실제 사용시점까지 미룬다,
val elapsedTime = measureTimeMillis {
delay(100)
}
println("async task-2 $elapsedTime ms")
}
println("start task-2")
job2.start()
}
- launch는 스레드 차단 없이 새 코루틴을 시작하고 결과로 job을 반환하는 코루틴 빌더이다.
- launch는 결과를 만들어내지 않는 비동기 작업에 적합하기 때문에 인자로 Unit을 반환하는 람다를 인자로 받는다.
- delay() 함수는 코루틴 라이브러리에서 정의된 일시 중단 함수이며, Thread.sleep()과 유사하지만, 현재 스레드를 차단하지 않고 일시 중단시키는 것에 차이가 있다(이때, 일시 중단된 스레드는 코루틴 내에서 다른 일시 중단 함수를 호출한다.)
- launch를 사용해 여러 개의 작업을 병렬적으로 수행할 수 있다.
- launch가 반환하는 job을 사용해 현재 코루틴을 상태를 확인하거나, 실행/취소가 가능하다.
- job.cancel()을 호출해 코루틴을 취소
- launch(start = CoroutineStart.Lazy)를 사용해 start 함수를 호출하는 시점에 코루틴을 동작시킴
- start 함수를 실행하지 않으면 launch 동작 X
async
fun sum(a: Int, b: Int) = a + b
//코틀린은 async / await를 키워드가 아닌 함수로 제공한다
fun main() = runBlocking<Unit> {
val result1 = async { //Deferred 라는 특별한 타입을 반환하고, 결과를 받아올 수 있는 await 함수를 제공한다.
delay(100)
sum(1, 3)
}
println("result1 : ${result1.await()}") //await 함수를 통해 비동기 결과를 사용할 수 있다.
val result2 = async {
delay(100)
sum(2, 5)
}
println("result2 : ${result2.await()}")
}
- async 빌더는 비동기 작업을 통해 결과를 만들어내는 경우 적합하다.
- async는 비동기 작업의 결과로 Deferred라는 특별한 인스턴스를 반환하는데, await라는 함수를 통해 async로 수행한 비동기 작업의 결과를 받아올 수 있다.
- JavaScript나 다른 언어의 async-await는 키워드인 반면, 코틀린의 코루틴은 async-await가 함수이다.
Suspend
suspend fun main() {
doSomething() //suspend를 일반 함수에서 사용할 수 없다.
//코루틴 스코프안에서만 사용이 가능
}
fun printHello() = println("hello")
suspend fun doSomething() = coroutineScope{//RunBlocking 과는 달리 현재 스레드가 블록킹되지 않고 스레드가 동작한다.
launch {
delay(200)
println("world!")
}
launch {
printHello()
}
}
- Suspend 함수는 코루틴의 핵심 요소로써 일시 중단이 가능한 함수이다.
- Suspend는 키워드이다.
- suspend 함수는 일반 함수를 마음껏 호출할 수 있지만, 일반 함수에서 suspend 함수를 호출할 수 없다.
- suspend 함수에서 async, launch와 같은 코루틴 빌더를 사용하려면 코루틴 스코프를 사용한다
- 코루틴 스코프를 사용하면 runBlocking과는 다르게 현재 스레드가 차단되지 않고 코루틴이 동작한다.
Flow
fun main() = runBlocking<Unit> {
val flow = simple()
//flow.collect { value -> println(value) }
println(flow) //참조값만 출력되고 코드가 동작하지 않는다(최종 연산자를 호출해야지만, 호출되기 떄문)
}
fun simple(): Flow<Int> = flow {
println("Flow started")
for (i in 1..3) {
delay(100)
emit(i) //데이터 통지
}
}
- Flow는 코루틴에서 리액티브 프로그래밍 스타일로 작성할 수 있도록 만들어진 API이다.
- 코루틴의 suspend 함수는 단일 값을 비동기로 반환하지만 Flow를 사용하면 여러 개의 값을 반환할 수 있다.
- 리액티브 스트림과 마찬가지로 최종 연산자인 collect를 호출하지 않으면 아무런 일도 일어나지 않는다.
728x90
'실무 프로젝트로 배우는 Kotlin & Spring > 스프링 WebFlux 이해하기' 카테고리의 다른 글
| 스프링 WebFlux의 코루틴 지원 (0) | 2022.12.11 |
|---|---|
| 스프링 데이터 R2DBC (0) | 2022.12.11 |
| 웹클라이언트 (0) | 2022.12.11 |
| 애노테이션 컨트롤러 (0) | 2022.12.11 |
| 함수형 엔드포인트 (0) | 2022.12.02 |