inflearn logo
강의

Course

Instructor

Coroutine that finishes in 2 hours

Lecture introduction video

suspend function의 일시 중단 여부는 어떻게 결정되나요?

505

mayday1001

3 asked

0

안녕하세요 강사님, 좋은 강의에 항상 감사드리고 있습니다!

 

다른게 아니라, 강의 중 suspend function은 일시 중단 되었다가 재개될 수도 있고 / 그렇지 않을 수도 있다고 설명 주셨습니다.

 

그렇다면 실제로 suspend function이 일시 중단되어야 하는지 여부는 어떻게 결정되나요?

단순히 suspend function 내부에서 또 다른 suspend function을 호출하기만 하면 무조건 일시 중단 되는 것인지, 아니면 Node.js 진영의 libuv 라이브러리처럼 비동기적으로 처리되어야 하는 IO 작업을 내부적으로 인지하는 방식이 별도로 구현되어 있는지 궁금합니다!

kotlin coroutine

Answer 2

2

junuuu

저도 Coroutine을 배우는 입장에서 이 부분이 조금 헷갈렸어서 추가적으로 글 작성해보겠습니다!

 

Kotlin docs의 coroutines 기본을 보다보면 launch에 대한 설명이 나옵니다.

https://kotlinlang.org/docs/coroutines-basics.html#your-first-coroutine

즉, launch는 새로운 Coroutine 만들어냅니다.

Coroutine을 대게 경량 쓰레드라고도 표현하니까 쓰레드로 예시를 들면 쓰레드 t1, t2가 경합하면 어떤것이 먼저 실행될까요? 아마 태현님이 말씀하신것처럼 OS나 내부 구현에 따라 달라질 것 같습니다.

 

저는 Spring 환경에서 테스트를 해보고있어서 다음과 같은 형식으로 코드를 작성했는데 임의로 delay() 메서드나 yield()로 요리조리 해보면 다양한 결과를 만날 수 있어서 이해가 조금 편했던것 같습니다.

@Component
class CoroutinesLecture1: ApplicationRunner {
    override fun run(args: ApplicationArguments?) {
        runBlocking {
            println("START")
            launch {
                newRoutine()
            }
            yield()
            println("END")
        }
    }

    suspend fun newRoutine(){
        val num1 = 1
        val num2 = 2
        println("${num1 + num2}")
    }
}

yield로 위임했기 때문에 START -> 3 -> END 결과

 

@Component
class CoroutinesLecture1: ApplicationRunner {
    override fun run(args: ApplicationArguments?) {
        runBlocking {
            println("START")
            launch {
                newRoutine()
            }
            yield()
            println("END")
        }
    }

    suspend fun newRoutine(){
        val num1 = 1
        val num2 = 2
        delay(50)
        println("${num1 + num2}")
    }
}

yield로 위임했지만 delay 메서드를 만났기 때문에 일시중단되어 START -> END -> 3 결과

 

글을 작성하다보니 저도 한가지 궁금한점이 생겼서 질문드립니다!

현재는 코루틴이 2개여서 중단과 재개가 눈에 잘 보이는 편이지만 만약 현업에서 코루틴이 N개 이상인 경우에서는 이런 과정들이 파악하기 힘들 것 같은데 코루틴끼리는 항상 동시에 실행될 것이라고 가정하고 코드를 작성하도록 컨벤션등이 있는지 궁금합니다!

 

틀린정보이거나 헷갈리는 부분있으시면 말씀해주세요!

늘 질좋은 강의 제공해주셔서 감사합니다ㅎㅎ

2

lannstark

안녕하세요! junuuu님! 😊 추가적으로 좋은 댓글 남겨주셔서 감사합니다! 😊 👍

현재는 코루틴이 2개여서 중단과 재개가 눈에 잘 보이는 편이지만 만약 현업에서 코루틴이 N개 이상인 경우에서는 이런 과정들이 파악하기 힘들 것 같은데 코루틴끼리는 항상 동시에 실행될 것이라고 가정하고 코드를 작성하도록 컨벤션등이 있는지 궁금합니다!

에 대해서 답변 드려 보자면,

 

"상황에 따라 조금 다를 수 있지만 대체로 동시에 실행될 수 있다는 것을 감안하고 코드를 작성한다"로 정리드릴 수 있을 것 같습니다.

예를 들어, 코루틴이 실행되려면 결국 "스레드"가 존재해야 하다 보니, 제가 수십개의 코루틴을 한 개의 스레드에서만 확정적으로 돌린다고 생각하고, 한 코루틴에 중단지점이 존재하지 않는다면 (혹은 blocking API만을 사용한다면) 여러 코루틴이 동시에 (concurrently) 돌아갈 경우가 없기 때문에 동시에 실행된다는 가정을 하지 않고 코드를 작성할 수 있습니다.

하지만 만약 멀티 스레드를 통해 여러 코루틴을 돌린다거나, 한 스레드에서 중단 지점이 존재하는 코루틴들을 돌린다면, 코루틴들이 동시에 돌아갈 수 있다 보니 thread-safe한 코드를 작성해야만 합니다!

 

thread-safe한 코드는 익히 아시는 것처럼

  • int 대신 AtomicInteger를 사용한다거나

  • 일반 컬렉션 대신 동시성 컬렉션을 사용한다거나

  • 불변 객체나 싱글톤을 활용한다거나 하는 등

     


    의 방법이 있는 것 같습니다! 😊

     

     

이렇게 말씀 드려보니 특별한 비법은 없는 것 같네요!! 😅

답변이 도움이 되었으면 좋겠습니다. 감사합니다! 🙇

1

junuuu

제가 궁금하던 부분의 핵심을 대답해주셔서 감사합니다!

말씀해주신 것 처럼 멀티 쓰레드인 Spring 환경에서 사용한다고 가정했을 때 코루틴은 여러 쓰레드에 점유될 가능성이 높으니 race-condition 문제를 잘 해결해주어야 겠네요(물론 기존에도 잘 고려해주어야 하지만)

 

감사합니다!

1

lannstark

안녕하세요! 잉G님! 정말 좋은 질문 감사드립니다! 😊

결론부터 말씀드리면, "suspend function이 호출되었을 때 중단될 필요성이 있으면 중단된다" 입니다. 예를들어 아래와 같은 코드를 실행시키면,

fun main(): Unit = runBlocking() {
  for (i in 1..2) {
    // START 출력
    newRoutine(i)
    // END 출력
  }
}

suspend fun newRoutine(i: Int) {
  // MIDDLE 출력
}

첫 번째 루프에서 START를 출력한 이후 중단 함수인 suspend fun이 호출되었으므로, 잠시 중단되고 두 번째 루프인 START가 먼저 출력될 수 있어 보이지만

실제로는 첫 번째 루프에서 START -> MIDDLE -> END가 모두 출력되고, 두 번째 루프의 START -> MIDDLE -> END가 출력되게 됩니다.

결론적으로는 중단될 필요성이 있으면 중단된다 라고 봐주시면 될 것 같습니다! 😊

 

답변이 도움이 되었으면 좋겠습니다. 감사합니다!! 🙏

1

mayday1001

강사님, 친절한 답변 감사합니다!
제가 아무래도 질문을 잘 못 드린 것 같아요, 제가 궁금한게 바로 그 중단될 필요성이었습니다...!

예시로 들어주신 코드의 경우, 머신이 코드를 실행할 때 newRoutine에서 중단할 필요가 없다고 판단하고 계속 실행한 것으로 보이는데, 요런 중단될 필요성을 판단하는 기준이 별도로 있는건가요?

1

lannstark

안녕하세요 잉G님!! 중단된 필요성 말씀이시군요!!

우선 제가 알고 있기로는 코루틴 내부 로직에 따른다고 알고 있긴 합니다! OS에서 프로세스를 스케쥴링 하는 것과 비슷한 느낌으로요! OS를 생각해보면, 저희가 A 프로세스 다음 어떤 프로세스가 실행될지 정확히 알 수 없죠!

어떤 코루틴을 중단시키고, 어떤 코루틴을 재개 시킬지는 코루틴의 내부 스케쥴러 구현에 따라 다르다 정도로 알아주시면 좋을 것 같습니다!

이와 관련해서 혹시나 저도 더 정보를 알게된다면, 꼭 추가 영상을 통해 안내해 드리도록 하겠습니다. 오늘도 좋은 하루 되세요! 감사합니다!! 🙏

Dispatchers 별 차이점 관련 질문

0

92

1

코루틴과 가상 스레드의 차이가 궁금합니다.

1

310

2

Coroutine과 ThreadLocal관련 질문

0

153

2

선생님 강의를 듣고 크롤링에 코루틴을 적용해보고 있습니다. 그런데 코루틴이 하나만 나와서 동시처리가 안되는데 혹시 봐주실 수 있나요??

1

115

1

7강에 대해서 궁금증이 있는데요

1

116

2

Spring MVC에서 corountine 활용 방안

1

540

1

9강 코루틴 중단과 재개관련 문의 드립니다.

0

124

2

suspend 함수에 관해 추가적인 질문 있습니다! (runcatching, Result)

0

126

1

간단 질문.. join() vs delay()

0

157

2

코루틴을 잘 사용하고 있는지 궁금합니다.

0

196

1

CoroutineScope & Dispatcher 질문

0

161

2

async await 관련 질문

1

136

2

코루틴 실행 순서 궁금합니다.

1

232

2

corutine task에 대한 질문

1

195

2

completing의 존재의의가 궁금합니다.

1

161

1

코루틴 dispatcher IO관련 질문

0

187

1

Job 질문이 있습니다

1

203

1

스프링 MVC 환경에서의 코루틴

1

2096

1

자식1, 2와 부모코루틴의 관계

1

225

1

한 suspend fun 의 반환값이 다른 suspend fun의 파라미터로 쓰일 때

1

329

2

delay 함수에 대해 질문이 있습니다

1

394

1

runBlocking을 사용하는 경우가 있을까요?

0

400

1

delay가 없으면 실행 안 되는 이유

0

295

1

코루틴 스코프

0

313

1