Idealim
article thumbnail
Published 2021. 8. 12. 12:12
[Kotlin] 코루틴(2) Coding Language/Kotlin

/* 본 게시물은 ' Do it 코틀린 프로그래밍 | with 황영덕 ' 의 내용을 토대로 작성되었습니다. */

참고 자료

[URL] :


#코루틴

 

1. 코틀린 코루틴의 디스패처(코루틴의 문맥)

코루틴은 항상 특정 문맥에서 실행된다. 이때 어떤 문맥에서 코루틴을 실행할지는 디스패처가 결정한다.

  • Dispatchers.Default : 기본 문맥인 CommonPool에서 실행되고 GlobalScope.launch{...} 와 launch(Dispatchers.Default){...} 는 같은 표현이다. 스레드를 새로 생성하지 않고 기존에 있는 것을 이용한다. 이는 연산 중심의 코드에 적합하다.
  • Dispatchers.IO :  입출력 위주의 동작을 하는 코드에 적합한 공유된 풀이다. 따라서 블로킹 동작이 많은 파일이나 소켓 I/O 처리에 사용하면 좋다.
  • Dispatchers.Unconfined : 호출한 컨텍스트를 기본으로 사용하는데 중단 후 다시 실행될 때 컨텍스트가 바뀌면 바뀐 컨텍스트를 따라 가는 특이한 디스패처이다. 이 옵션의 사용은 권장하지 않는다.
  • Dispatchers.Main : 안드로이드 기본 스레드에서 코루틴 실행. UI와 상호작용에 최적화됨.

2. 기본 동작 제어하기

코루틴으로 시간을 세는 반복함수를 만들어보자.

fun main() { runBlocking {
    GlobalScope.launch {  // 만일 launch만 사용하면 종료되지 않음
        repeat(1000){
            println("time: $it")
            delay(1000L)
            }
        }
        delay(3000L)
    }
}

실행 결과

GlobalScope.launch
launch

GlobalScope로 생명주기를 한정했기 때문에 첫 번째 결과는 2까지만 출력하고 종료되었지만 GlobalScope를 지우면 모든 횟수를 진행할 때까지 프로그램이 종료되지 않는다.

 

코루틴 작업 취소하기

cancel() 함수를 사용해보자.

fun main() { runBlocking {
    val job = launch {  // 만일 launch만 사용하면 종료되지 않음
        repeat(1000){
            println("time: $it")
            delay(1000L)
            }
        }
        delay(3000L)
        job.cancel()
    }
}

cancel() 함수에 의해 3초 뒤 repeat() 함수의 반복 실행이 취소된다.

 

finally 실행 보장

try~finally 구문을 사용해 finally 블록에서 코루틴의 종료 과정을 처리하도록 할 수 있다. 단 finally 블록에 식나이 걸리는 작업이나 지연 함수가 사용될 경우 실행을 보장하기 위해서는 NonCancellable 문맥에서 작동해야한다. 이것을 위해 withContext(NonCancellable){...} 을 사용해야한다.

fun main() { runBlocking {
    val job = launch {
        try {
            repeat(1000) {
                println("time: $it")
                delay(1000L)
            }
        } finally { // finally의 완전한 실행 보장
                withContext(NonCancellable){
                    println("finally start")
                    delay(1000L) //NonCancellable 문맥에서 지연 함수 사용가능
                    println("Non-cancel")
                }
            }
        }
        delay(3000L)
        job.cancelAndJoin()
        println("Exit")
    }
}

실행 결과

실행 상태의 판단

만일 코드를 중단하기 위해 코루틴에 조건식을 넣으려고 할 때 연산이 마무리되기 전까지는 조건식에 의해 루틴이 중단되지 않는다는 것을 기억해야 한다. 

fun main() { runBlocking {
    val startTime = System.currentTimeMillis()
    val job = GlobalScope.launch {
            var nextPrintTime = startTime
            var i = 0
            while(i < 5){ //코루틴에 조건식을 넣으면 연산이 마무리 되기 전까지 조건식에 의해 루틴이 중단되지 않는다.
                if(System.currentTimeMillis() >= nextPrintTime){
                    println("${i++}")
                    nextPrintTime += 1000L
                }
            }
        }
    delay(2000L)
    println("main: 2second gone")
    job.cancelAndJoin()
    println("main: Quit")
    }
}

실행 결과

결과로 보아 조건문의 연산이 완료되기 전까지 코루틴에서 탈출을 못하는 것을 확인할 수 있다. 이를 해결하기 위해서는 while(i<5) 대신 while(isActive)을 사용하면 해결이 가능하다.

반응형
profile

Idealim

@Idealim

읽어주셔서 감사합니다. 잘못된 내용이 있으면 언제든 댓글로 피드백 부탁드립니다.