Notice
Recent Posts
Recent Comments
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

훌륭한 개발자가 되기 위하여

코루틴 이해하기 본문

안드로이드

코루틴 이해하기

jay20033 2025. 1. 14. 19:45

루틴 : 특정한 일을 하기 위한 일련의 처리 과정 (함수 or 매서드)

서브루틴 : 함수 내에서 함수가 호출될 경우 호출된 함수

fun routine() {
		routineA() // routineA는 routine의 서브루틴
		routineB() // routineB는 routine의 서브루틴
}
  • 서브루틴은 한 번 실행되면 끝까지 실행된다.
  • 루틴에 의해 서브루틴이 호출되면 루틴을 실행하던 스레드는 서브루틴을 실행하는데 사용되어 서브루틴의 실행이 완료될 때까지 다른 작업을 할 수 없다.

 

코루틴 : 함께 실행되는 루틴으로 서로 간에 스레드 사용을 양보하며 함께 실행된다.

fun main() = runBlocking<Unit> {
    launch {
        while (true) {
            println("자식 코루틴에서 작업 실행 중")
            yield()
        }
    }

    while (true) {
        println("부모 코루틴에서 작업 실행 중")
        yield()
    }
}

코루틴의 스레드 양보

  • 코루틴은 작업 중간에 스레드의 사용이 불필요해지면 스레드를 양보한다.

       👉 이 때 양보된 스레드는 다른 코루틴이 점유해 사용할 수 있다.

  • 스레드를 양보하는 주체는 코루틴이다.

       👉 스레드를 양보하기 위해서는 코루틴이 직접 스레드 양보를 위한 함수를 호출해야 한다.

delay 함수

  • 작업을 일정 시간 동안 일시 중단해야 할 경우 delay 함수 를 사용할 수 있다.
  • 코루틴이 delay함수를 호출하면 코루틴은 사용하던 스레드를 양보하고 설정된 시간 동안 일시 중단된다.
fun main() = runBlocking<Unit> {
    val startTime = System.currentTimeMillis()
    repeat(10) { repeatTime ->
        launch {
            delay(1000L)
            println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료")
        }
    }
}

fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"

 

✔ Thread.sleep 함수를 사용하면 스레드를 양보하지 않는다.

fun main() = runBlocking<Unit> {
    val startTime = System.currentTimeMillis()
    repeat(10) { repeatTime ->
        launch {
            Thread.sleep(1000L)
            println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료")
        }
    }
}

fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"

join, await

  • Job의 join 함수나 Deferred의 await 함수가 호출되면 해당 함수를 호출한 코루틴은 스레드를 양보하고, join 또는 await의 대상이 된 코루틴이 완료될 때까지 일시 중단된다.
  • 하나의 코루틴이 스레드를 양보하지 않으면 다른 코루틴은 스레드를 점유하지 못한다.
fun main() = runBlocking<Unit> {
    val job = launch {
        println("1. launch 코루틴 작업이 시작됐습니다.")
        delay(1000L)
        println("2. launch 코루틴 작업이 완료됐습니다.")
    }
    println("3. runBlocking 코루틴이 곧 일시 중단 되고 메인 스레드가 양보됩니다")
    job.join()
    println("4. runBlocking이 메인 스레드에 보내져 작업이 다시 재개됩니다")
}

yield 함수

  • 몇가지 상황에서는 yield 함수 를 통해 직접 스레드를 양보하는 것이 필요하다
  • 특히, 단일 스레드만 사용하는 상황에서는 명시적으로 yield를 사용해야 하는 경우가 종종 생긴다.
fun main() = runBlocking<Unit> {
		val job = launch {
				while(this.isActive) {
						println("작업 중")
				}
		}
		delay(100L)
		job.cancel()
}

launch 코루틴에 스레드를 양보하는 부분이 없기 때문에 job.cancel() 이 실행되지 않음

// 실행 결과
작업 중
작업 중
작업 중
...

취소 되는 코드

fun main() = runBlocking<Unit> {
    val job = launch(Dispatchers.Default) {
        while (this.isActive) {
            println("작업 중")
        }
    }
    delay(100L)
    job.cancel()
}

코루틴의 실행 스레드

  • 코루틴이 일시 중단된 후 재개되면 CoroutineDispatcher 객체는 재개된 코루틴을 다시 스레드에 보낸다.
  • 이 때, CoroutineDispatcher 객체는 코루틴을 사용할 수 있는 스레드 중 하나에 보내기 때문에, 코루틴이 재개된 후의 실행 스레드는 일시 중단되기 전의 스레드와 다를 수 있다.
  • 코루틴의 실행 스레드는 고정이 아니다
  • 스레드를 양보하지 않으면 실행 스레드가 바뀌지 않는다.