Kotlin 코루틴의 다양한 형태

Jonghwan Choi·2023년 6월 5일
0

공식 문서
Coroutine이란 비동기 작업이 필요한 상황에서 Java의 thread 대신 사용하기 위해 Kotlin에서 기본 라이브러리로 제공하는 경량 스레드이다. 다양한 상황에서 사용할 수 있도록 아주 다양한 형태가 존재하는데, 전부 써보지는 않아서 지금까지 써본 것들만 기록하겠다.

코루틴 사용을 위해서는 상황에 맞는 scope와 dispacher를 지정해 주어야 한다. 이 둘을 개발자가 지정할 필요 없이 미리 정해져 있는 형태도 존재한다. scope와 dispather의 의미와 종류는 다음과 같다.

Scope

코루틴의 생명주기

CoroutineScope(Dispachers)

작업이 끝나면 생명주기가 끝남

ViewModel.viewModelScope

해당 뷰모델 객체의 생명주기를 따름

LifecycleOwner.lifecycleScope

해당 라이프사이클오너 객체의 생명주기를 따름

GlobalScope

앱의 생명주기를 따름

Dispachers

코루틴이 할당될 스레드풀 종류. 프레임워크 종속적임

Default

안드로이드 기본 스레드풀. CPU를 많이 쓰는 작업에 최적화 (데이터 정렬, 복잡한 연산 등...)

IO

데이터 입출력 작업에 최적화 (네트워킹, 파일 입출력 등...)

Main

안드로이드 메인 스레드. UI작업만 하는 게 좋음
안드로이드의 Looper.getMainLooper() 메서드를 사용 → 프레임워크 종속

Unconfined

자신을 호출한 context에서 돌아가다가 한번 정지가 되고 나면 해당 정지를 수행한 스레드로 옮겨가서 재동작한다.

사용 형태

launch { }

리턴값을 받을 필요 없는 작업시 사용 (==블로킹 불가)
Job이라는 리턴값이 있는데 이걸로 cancel()과 join() 가능

CoroutineScope(Dispachers.IO).launch { 
    // do something
}

async { }

리턴값을 받아 후속 작업을 해야 하는 작업시 사용 (==블로킹 가능)

CoroutineScope(Dispachers.Default).launch {
    val deferred = async(Dispachers.IO) {
        // do something
    }
    ...
    deferred.await() // async 블록의 작업이 모두 끝난 후 실행
}

suspendCancellableCoroutine

콜백함수의 결과물을 리턴값으로 받게 해서 비동기 작업을 동기 작업처럼 코딩할 수 있게 해줌.
콜백 지옥 해소, 가독성 향상

콜백함수 부분

suspend fun doSomething(): Result {
    return suspendCancellableCoroutine { continuation -> 
        val id = Library.doSomething(object : Listener {

            override fun onSuccess(result: Result) {
            	// 비동기작업 중 취소, 에러 없으면 여기가 Result가 됨
                continuation.resume(result) 
            }

            override fun onError(throwable: Throwable) {
            	// 비동기작업 중 에러가 나면 여기가 Result가 됨
                continuation.resumeWithException(throwable)
            }
        })

        continuation.invokeOnCancellation { 
            Library.cancel(id) // 비동기작업 중 취소하면 여기가 Result가 됨
        }
    }
}

콜백 호출 부분

CoroutineScope(Dispachers.IO).launch { 
    // 비동기작업을 동기작업처럼 코딩 가능 == 가독성 향상
    val result = doSomething()
}

withContext(coroutineContext) { }

코루틴 안에 위치한 비동기 작업을 해당 코루틴 안의 다른 작업과 동기적으로 수행하도록 하고 싶을 경우 사용
자신을 감싼 코루틴의 디스패처와 다른 종류의 디스패처를 컨텍스트로 지정할 경우 새로 디스패치한 후 작업 완료시 원래 디스패처로 돌아감

CoroutineScope(Dispatchers.IO).launch {
    val response = withContext(Dispatchers.IO) {
        client.newCall(request).execute()
    }
}
profile
유니티 게임 클라이언트 개발자를 꿈꾸는 뉴비

0개의 댓글