Error rendering WebPanel: No renderer found for resource type: velocity Template contents: <meta name="ajs-keyboardshortcut-hash" content="$keyboardShortcutManager.shortcutsHash">
메타 데이터의 끝으로 건너뛰기
메타 데이터의 시작으로 이동

왜 코루틴을 써야하나요?

코루틴을 써야하는 이유는 여러가지가 있지만 그 중에서도 가장 중요하게 꼽히는 이유가 비동기 프로그래밍입니다. 기존 방식들인 Thread, 콜백 함수, Future, Promise, Rx를 썼을 때보다 읽기 쉬운 코드를 쓸 수 있습니다.

Thread 사용

fun requestToken(): Token { 
    // 요청을 보내고 기다렸다가(Thread block) 응답을 받은 후 반환
    return token
}
fun createPost(token: Token, item: Item): Post {
    // 요청을 보내고 기다렸다가(Thread block) 응답을 받은 후 반환
    return post
}
fun processPost(post: Post) { /* 비즈니스 로직 */ }

fun postItem(item: Item) {
    val token = requestToken()  // Thread block
    val post = createPost(token, item) // Thread block
    processPost(post)
}


콜백 사용

fun requestTokenAsync(cb: (Token) -> Unit) { 
    // 요청을 보내고 응답이 오면 콜백함수 호출
    cb(token)
}
fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) {
    // 요청을 보내고 응답이 오면 콜백함수 호출
    cb(post)
}
fun processPost(post: Post) { /* 비즈니스 로직 */ }

fun postItem(item: Item) {
    requestTokenAsync { token ->
        createPostAsync(token, item) {
            processPost(post)
        }
    } // 콜백 지옥
}

Future 사용

fun requestTokenAsync(): CompletableFuture<Token> {
    // 요청을 보내고 Future를 즉시 반환
    return future
}
fun createPostAsync(token: Token, item: Item): CompletableFuture<Post> {
    // 요청을 보내고 Future를 즉시 반환
    return future
}
fun processPost(post: Post) { /* 비즈니스 로직 */ }

fun postItem(item: Item) {
    requestTokenAsync()
        .thenCompose { token -> createPostAsync(token, item) }
        .thenAccept { post -> processPost(post) }
    // 본인이 쓰려는 Future, Promise, Rx의 수많은 함수들을 알아보고 공부해야 함
    // CompletableFuture, ListenableFuture, Reactor, RxJava
}


Kotlin Coroutines 사용

suspend fun requestToken(): Token {
    // 요청을 보내고 기다렸다가(coroutine suspend) 응답을 받은 후 반환
    return token
}
suspend fun createPost(token: Token, item: Item): Post {
    // 요청을 보내고 기다렸다가(coroutine suspend) 응답을 받은 후 반환
    return post
}
fun processPost(post: Post) { /* 비즈니스 로직 */ }

suspend fun postItem(item: Item) {
    val token = requestToken()  // coroutine suspend
    val post = createPost(token, item) // coroutine suspend
    processPost(post)
    // Thread block 방식의 코드와 똑같음
}



코루틴은 무엇인가요?

코루틴은 실행이 일시중지(suspend)되고 재개(resume)될 수 있도록 하는 협동 멀티태스킹을 위한 서브루틴을 일반화하는 컴퓨터 프로그램 구성 요소입니다.

협동 멀티태스킹은 운영 체제가 실행중인 프로세스에서 다른 프로세스로 컨텍스트 전환을 하지 않는 컴퓨터 멀티 태스킹 스타일입니다.

서브루틴은 특정 작업을 수행하는 일련의 프로그램 명령입니다. 여러 프로그래밍 언어에서 서브 루틴은 procedure, function, method, subprogram으로 불립니다.

일시중지(suspend)되고 재개(resume)된다는게 무슨 뜻인가요?

자바의 쓰레드와 비교해보겠습니다. DB 호출이나 REST API 요청과 같이 쓰레드가 block 상태였다가 다시 돌아와서 작업을 처리하는 경우와 유사합니다. 중요한 차이점은 suspend는 쓰레드를 block하지 않는다는 것입니다.

코틀린 공식 홈페이지에서는 코루틴을 가벼운 쓰레드(light-weight thread)라고 표현합니다. 아래는 코루틴 10만개를 만들어서 각각의 코루틴이 .을 출력하는 코드입니다. 실제로 실행해봐도 이상없이 제대로 동작합니다.

import kotlinx.coroutines.*

fun main() = runBlocking {
    repeat(100_000) {
        launch {
            delay(1000L)
            print(".")
        }
    }
}



하지만 위 코드를 쓰레드로 바꾸어서 실행해보면 굉장히 좋은 사양이 아니라면 대부분 메모리 부족으로 실패합니다.

import kotlin.concurrent.thread

fun main()  {
    repeat(100_000) {
        thread {
            Thread.sleep(1000L)
            print(".")
        }
    }
}


실습

https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels/01_Introduction

1장에서 GitHub 저장소 clone한 뒤에 TODO 주석이 붙어 있는 부분 구현
4장 - Using suspend functions

참고

  • 레이블 없음

4 댓글

  1. 실습 중 인터넷 느릴 때 사용할 mock-server

    jar 파일 다운로드 받고 java -jar xxx.jar 실행 후
    baseUrl을 http://localhost:8080으로 수정

    val retrofit = Retrofit.Builder()
            .baseUrl("http://localhost:8080")
            .addConverterFactory(JacksonConverterFactory.create(jacksonObjectMapper()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(httpClient)
            .build()