본문 바로가기
개발

[Kotlin] coroutine

by 지리오 2026. 10. 4.

용어 정리

  • blocking
var data = getData() // 1
println(data)// 2
  1. 데이터를 반환하는 함수의 리턴값을 변수에 할당.
  2. 데이터를 사용할 수 있게 되면 데이터가 출력됨.

데이터를 완전히 얻을 때 까지 프로그램이 멈추게 된다 (1~2 사이) 이를 블로킹작업이라고 한다.

  • 병렬성 : 코딩을 하면서 음악을 듣기 (’손’과 ‘귀’을 동시에 사용) - 멀티코어 프로세서의 멀티스레드
  • 동시성 : 코딩을 하면서 과자를 먹기 (손을 ‘키보드’와 ‘과자’에 사용) - 코루틴

1. Coroutine이란?

  • 애플리케이션을 개발하는 동안 네트워크, 데이터베이스호출 또는 복잡한 계산, api호출, 데이터 다운로드 등등..과 같이 긴 시간에 걸쳐 작업을 수행해야하는 상황이 자주 발생할때 사용한다.
  • 백그라운드에서 또는 비동기적으로 위와같은 작업이 시행되게 할 수 있음. → 사용자를 기다리게 하지 않고 웹(앱)을 사용할 수 있게해준다

cf.) Java의 Thread, C#의 async/await

2. Coroutine builders

  • Scope

CoroutineScope GlobalScope

runBlocking 최상위함수 최상위함수
launch 확장함수 확장함수(권장x)
async 확장함수 확장함수(권장x)
  • CoroutineScope : 다른 상태를 공유하기 위해 사용한다.
    • CoroutineStart - DEFAULT, LAZY, ATOMIC, UNDISPATCHED

 

 

  1.  runBlocking
    • 명령줄 검증, 테스트
    • 현재 스레드를 block하고 모든 내부 코루틴이 종료될때 까지 블록한다.
    • 사용하지 않는 것이 좋다고 함
    코루틴에서 runBlocking 은 사용하지 않는것이 좋습니다.
    • 예시
    • fun <T> runBlocking(block: suspend CoroutineScope.() -> T): T
  2. launch
    • 독립된 프로세스 실행, 해당 코루틴에서 리턴값을 받을 필요가 없을 때 유용
    • CoroutineScope의 확장함수이기때문에 CoroutineScope이 사용 가능한 경우에만 사용가능
    • 코루틴 취소가 필요할 때 사용할 수 있는 Job인스턴스를 리턴한다.
    • 예시
    • fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job
    1. async빌더
      • 리턴값이 필요할 때 유용 → await() 을 붙힌 값이 리턴값이다.
      • 예시
      • fun <T> CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T>
      • 리턴값인 Deferred<T>는 생산된 값을 리턴하기 전에 코루틴이 완료될때 까지 기다리는 await함수이다.

Job 인스턴스


 

3. Suspend Function

실행을 잠시 중단하고 자신의 작업을 끝내면 중단했던 작업을 계속 할 수 있는 함수

suspend fun thisIsSuspend(arg: String) : Boolean{
	//~~
}

코루틴은 적어도 한 개 이상의 suspend 함수를 필요로 한다.

 

4. Dispatcher

  • 코루틴이 실행될 스레드를 결정하는데, 여기에는 시작될 곳과 중단후 다시 시작될 곳을 모두 포함한다.
    • Default :
    • Main
    • Unconfined : 첫번째 중단지점에 도달할 때까지 현재 스레드에 있는 코루틴을 실행한다. 코루틴은 일시중지된 후에, 일시중단연산에서 사용된 기존 스레드에서 다시 시작된다.
    • IO
    • newSingleThreadContext() : 일시 중지후에도 항상 같은 스레드에서 실행된다.
    • ndwFixedThreadPoo;Context() : 스레드풀에서 알아서 부하분산을 위한 방법을 정함
    • 예외처리
    • val handler = CoroutineExceptionHandler({context, throwable -> println("$context") println("$throwable.message") }) GlobalScope.launch(handler){ //~~ }

 

5. 연습

  • 아래와 같은 함수를 코루틴을 이용해서 요청시간을 단축시켜보려고 한다.

 

private fun first(): Long {
    println("1st function started")
    Thread.sleep(1000L)
    println("1st function ended")
    return 1L
}

private fun second(num: Long): String {
    println("2nd function started")
    Thread.sleep(2000L)
    println("2nd function ended")

    if (num != 1L) {
        return "no"
    }

    return "2"
}

private fun third(str: String): Boolean {
    println("3rd function started")
    Thread.sleep(1500L)
    println("3rd function ended")

    return str === "2"
}

fun main() {
    val startTime = System.currentTimeMillis()

    val firstVal = first()
    val secondVal = second(firstVal)

    println(third(secondVal))

    println(System.currentTimeMillis() - startTime)
}

 

  • 코루틴 → async
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO

private suspend fun first() : Long{
    println("1st function started $")
    delay(1000L)
    println("1st function ended")
    return 1L
}

private suspend fun second(long: Deferred<Long>) : String{
    println("2nd function started")
    delay(2000L)
    println("2nd function ended")

    if(long.await()===1L){
        return "success!"
    }

    return "nope"
}

private suspend fun third(str: Deferred<String>) {
    println("3rd function started")
    delay(1500L)
    println("3rd function ended")
    println("done! ${str.await()}")
}

fun main() = runBlocking {

    val startTime = System.currentTimeMillis()

    val firstVal = async(IO) {
        first()
    }

    val secondVal1 = async(IO) {
        second(firstVal)
    }

    third(secondVal1)
    println(System.currentTimeMillis() - startTime)

}

 

원자적 데이터 구조

  • 원자성 : 어떠한 작업이 실행될때 언제나 완전하게 진행되어 종료되거나, 그럴 수 없는 경우 실행을 하지 않는 경우
val counter = AtomicInteger()

fun asyncIncrement(by: Int) = async {
	for(i in 0 until by) {
		counter.incrementAndGet()
	}

 

 

참고자료 :코틀린 쿡북, 코틀린 동시성 프로그래밍

https://www.youtube.com/watch?v=_hfBv0a09Jc

https://webcache.googleusercontent.com/search?q=cache:wB0yjshjhe0J:https://codechacha.com/ko/android-coroutine/+&cd=17&hl=ko&ct=clnk&gl=kr

'개발' 카테고리의 다른 글

[Spring] spring security  (0) 2026.10.04
[JPA] hibernate  (0) 2026.10.04
[Springboot] htmlConverter사용해서 pdf파일 만들기(+한글폰트설정)  (0) 2021.07.29
[etc] Error Domain=NSPOSIXErrorDomain Code=86  (0) 2021.06.21
[SQL] QueryDSL  (0) 2021.06.16