인프런 커뮤니티 질문&답변

denia park님의 프로필 이미지
denia park

작성한 질문수

코틀린 코루틴 완전 정복

coroutineScope 관련 질문 및 실제 사용 사례에 대한 질문

해결된 질문

작성

·

73

·

수정됨

1

안녕하세요. 강사님

 

강사님 덕분에 코루틴에 대한 이해도가 많이 높아져서, 최근 코루틴을 활용한 비동기 서버 구현에 대해서 재밌게 개발을 하고 있습니다. (코루틴이 재미는 있는데, 비동기라는 개념 때문에 너무 어려워서 머리가 아프네요 😢)

 

spring webflux와 코루틴을 활용한 서버 개발을 하다보니, 자연스럽게 suspend 키워드가 많이 사용되고 일시 중단 함수에 대해서 조금 더 높은 이해도가 필요해서 이에 대해서 몇가지 질문을 하려고 합니다.

 

1.저는 강사님의 일시 중단 함수 관련 강의를 듣고

일시 중단 함수란 그냥 일시 중단 지점을 포함할 수 있는 특이한 함수,
suspend 함수에서 코루틴을 사용하기 위해서는 coroutineScope을 사용하자

이렇게 이해를 했어서 다음과 같이 코드를 짰습니다.

class SuspendRequestTest {
    @Test
    fun suspendRequestTest() = runBlocking {
        val startTime = System.currentTimeMillis() // 시작 시간 기록

        println("suspendRequest start")

        anotherSuspendFunction1() // suspend function 1 호출
        anotherSuspendFunction2() // suspend function 2 호출

        println("suspendRequest end")

        val endTime = System.currentTimeMillis() // 종료 시간 기록
        println("suspendRequest elapsed time: ${endTime - startTime} ms") // 경과 시간 출력
    }

    private suspend fun anotherSuspendFunction1() = coroutineScope {
        println("anotherSuspendFunction1 start")

        launch {
            println("anotherSuspendFunction1 extra logic start")
            delay(1000)
            println("anotherSuspendFunction1 extra logic end")
        }

        println("anotherSuspendFunction1 end")
    }

    private suspend fun anotherSuspendFunction2() = coroutineScope {
        println("anotherSuspendFunction2 start")

        launch {
            println("anotherSuspendFunction2 extra logic start")
            delay(1000)
            println("anotherSuspendFunction2 extra logic end")
        }

        println("anotherSuspendFunction2 end")
    }
}
// 실행 로그
suspendRequest start
anotherSuspendFunction1 start
anotherSuspendFunction1 end
anotherSuspendFunction1 extra logic start
anotherSuspendFunction1 extra logic end
anotherSuspendFunction2 start
anotherSuspendFunction2 end
anotherSuspendFunction2 extra logic start
anotherSuspendFunction2 extra logic end
suspendRequest end

suspendRequest elapsed time: 2037 ms

제 예상대로라면 1초가 살짝 넘는 시간으로 작업이 완료되어야 하는데, 해당 작업은 2초가 걸리는 작업이었습니다. (로그도 항상 1번이 먼저 나타납니다.)

1-1) 혹시 coroutineScope은 내부의 코드가 완료되기 전까지는 다음으로 넘어가지 않는 Blocking 속성을 가지는 함수일까요 ?

1-2) supervisorScopecoroutineScope 처럼 내부의 코드가 완료되기 전에는 다음으로 넘어가지 않는다고 알면 될까요?

1-3) 일시 중단 함수가 여러 일시 중단 함수들을 내부 로직으로 가지는 경우, 순차적으로 각각의 일시 중단 함수가 끝나야지만 다음 일시 중단 함수가 실행되는 걸까요 ?

2.제가 실제 코루틴 사용 사례 및 코드를 많이 보지 못해서, 어떻게 쓰는게 좋은 케이스 인지 이해도가 낮은 것 같습니다. 보통 coroutineScope 혹은 supervisorScope함수들은 어떤 경우에 어떤 목적을 위해 주로 쓰이는 걸까요 ??

coroutineScope의 속성이나 특징에 관해서 추가적으로 제가 알아야 하거나 참고하면 좋을 자료가 있을까요?? 😊

 

답변 3

2

조세영님의 프로필 이미지
조세영
지식공유자

denia park님 안녕하세요. 지식 공유자 조세영입니다.

질문하신 부분 날리는달님께서 잘 답변해주신것 같습니다. 깊은 부분까지 모두 답변해주셔서 답변을 참고해주시면 감사할 것 같습니다.

날리는달님 감사합니다!

denia park님의 프로필 이미지
denia park
질문자

날리는 달님의 답변 확인 후 몇가지 추가적인 질문이 있습니다!

 

1) supervisorScopecoroutineScope 처럼 비슷한 목적으로 사용이 되지만, 자식 코루틴의 예외를 전파하지 않는다는 특성을 가진다고만 이해하면 될까요 ??

2) coroutineScope안에서 같이 묶어서 실행할 작업 없이 딱 1가지의 작업만을 한다면, 그냥 withContextasync.await, launch.await를 쓰는게 나을까요?

3) 혹시 강사님께서 참조하시는 코루틴 관련 깃헙 프로젝트 같은게 있을까요?? 좋은 코드 패턴 같은 것들을 학습하는 용도로 사용하려고 합니다.

조세영님의 프로필 이미지
조세영
지식공유자

1) supervisorScopecoroutineScope 처럼 비슷한 목적으로 사용이 되지만, 자식 코루틴의 예외를 전파하지 않는다는 특성을 가진다고만 이해하면 될까요 ??

답변: 네 맞습니다!

2) coroutineScope안에서 같이 묶어서 실행할 작업 없이 딱 1가지의 작업만을 한다면, 그냥 withContextasync.await, launch.await를 쓰는게 나을까요?

네 coroutineScope은 범위를 만들 때 사용하는 것이 일반적이기 때문에, 만약 한 가지 작업만을 한다면 withContext를 사용하는 것이 좋을 것 같습니다.

3) 혹시 강사님께서 참조하시는 코루틴 관련 깃헙 프로젝트 같은게 있을까요?? 좋은 코드 패턴 같은 것들을 학습하는 용도로 사용하려고 합니다.

코루틴 공식 문서를 제외하고는 코루틴을 학습할 수 있는 깃헙 프로젝트나 오픈소스 프로젝트는 따로 없는 것으로 알고 있습니다. (다만 제가 잘 모르는 프로젝트가 있을 수 있습니다)
제가 코루틴 관련 책을 쓰고 강의를 만들게 된 계기가 학습 자료가 찾아보기가 너무 어렵기 때문이었는데요. Best Practice를 정리한 깃헙 프로젝트가 있다면 정말 좋을 것 같네요. 이 부분에 대해서도 한 번 자료를 만들어 볼 수 있을지 고민해 볼 수 있도록 하겠습니다.

denia park님의 프로필 이미지
denia park
질문자

정말 감사합니다😀

2

안녕하세요. 대신 답변해드립니다!!

coroutineScope는 주어진 블록과 모든 자식 코루틴이 끝날때까지 대기하는 함수입니다.
여러 코루틴 스코프를 구조화하고 관리하기 위해 사용됩니다.

suspend함수는 코루틴이 아니기 때문에 빌더함수를 통해 동시성을 관리해야 합니다.
중단지점은 코루틴이 일시 중단되고 다른 코루틴이 해당 스레드에서 실행될 수 있는 지점입니다.
중단 지점 자체는 동시성을 지원하지 않으며, 동시성은 async, launch, 또는 Dispatchers와 같은 도구에 의해 관리됩니다.

launch는 코루틴 단일 작업, coroutineScope는 동시 작업의 묶음을 관리하는 상위 추상화라고 볼 수 있습니다.

suspend fun callAbByCoroutineScope(): String = coroutineScope {
    val a = async { callA() }
    val b = async { callB() }
    a.await() + b.await() // AB 결과 반환
}

suspend fun callDWithDependencies(): String = coroutineScope {
    val abDeferred = async { callAbByCoroutineScope() }
    val cDeferred = async { callC() }
    callD(abDeferred.await(), cDeferred.await()) // D 호출
}


AB호출을 추상화 하려면 callAbByCorouineScope()로 묶고

D호출을 추상화하려면 해당 3줄을 coroutineScope()로 묶는거죠

 

만약 사용하는 API가 논블로킹 방식(WebClient)이 아니라 블로킹 방식(RestTemplate)이라면, 호출 중 해당 작업 스레드가 대기 상태로 블로킹됩니다.

denia park님의 프로필 이미지
denia park
질문자

예제까지 들어가며 설명해주셔서 이해가 잘 됐습니다.

정말 감사합니다!!

1

안녕하세요, 인프런 AI 인턴입니다. denia park님.

코루틴과 관련하여 심도 깊은 질문을 주셔서 감사합니다. 코루틴을 사용한 비동기 프로그래밍은 처음에는 복잡해 보일 수 있지만, 그 개념을 이해하게 되면 많은 도움이 됩니다.

  1. 일시 중단 함수 실행에 대한 이해

1-1) coroutineScope 함수는 블록 내부의 모든 코루틴이 완료될 때까지 종료되지 않습니다. 블로킹하지 않지만, 코루틴 스코프 내의 작업들이 모두 끝나기 전에는 다음 코드로 진행되지 않는다는 것이 맞습니다. 따라서 비동기적으로 실행되더라도 코드가 스코프를 벗어나지 않는 동안은 스케줄링된 모든 작업을 기다립니다. 다시 말해, launch로 시작되는 코루틴 블록 안의 작업들이 있을 경우 이들이 완료될 때까지 기다립니다.

1-2) supervisorScope 또한 coroutineScope와 유사하게 블록 내의 모든 코루틴이 완료될 때까지 블록을 종료하지 않습니다. 그러나 supervisorScope는 하위 코루틴의 실패가 다른 하위 코루틴에 전파되지 않도록 허용하는 차이가 있습니다. 즉, 상위 스코프를 취소하지 않고도 개별 하위 코루틴의 실패를 허용합니다.

1-3) 여기에 주어진 사례에서는 여러 suspend 함수를 순차적으로 호출하는 경우 각 함수가 완료된 후에 다음 함수가 호출됩니다. 만약 각 함수 내에서 다른 작업이 비동기적으로 실행되었다면, 해당 비동기 작업이 완료되기 전까지는 다음 코드로의 진행이 이루어지지 않을 수 있습니다.

  1. coroutineScopesupervisorScope의 사용 사례

coroutineScope:
- 하위 코루틴들이 완료될 때까지 결속력을 유지하고 싶을 때 사용합니다.
- 코루틴 내에서 특정 범위의 작업들을 그룹핑하여 처리할 때 유용하며, 안전하게 중단점에서 상위 함수가 종료되지 않도록 보장합니다.

supervisorScope:
- 실수로 발생할 수 있는 하위 코루틴의 오류가 전체 코루틴 스코프를 취소하지 않도록 하고 싶을 때 사용합니다.
- 대부분의 경우 한 하위 작업이 실패하더라도 나머지 작업이 영향을 받지 않고 계속 진행되어야 할 때 활용합니다.

추가 참고 자료
- Kotlin Coroutines 공식 문서: 코루틴의 기본 개념을 이해하는 데 매우 유용한 자료입니다.
- Coroutines Overview: 코루틴의 개요와 다양한 사용 사례를 제공합니다.
- Coroutine Context and Dispatchers: 코루틴의 실행 컨텍스트와 디스패처에 대해 더 깊이 알아볼 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

denia park님의 프로필 이미지
denia park

작성한 질문수

질문하기