• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

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

23.12.15 16:09 작성 조회수 230

0

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

 

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

 

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

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

답변 2

·

답변을 작성해보세요.

2

junuuu님의 프로필

junuuu

2024.01.07

저도 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개 이상인 경우에서는 이런 과정들이 파악하기 힘들 것 같은데 코루틴끼리는 항상 동시에 실행될 것이라고 가정하고 코드를 작성하도록 컨벤션등이 있는지 궁금합니다!

 

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

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

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

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

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

 

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

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

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

 

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

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

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

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

     


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

     

     

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

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

junuuu님의 프로필

junuuu

2024.01.07

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

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

 

감사합니다!

1

안녕하세요! 잉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가 출력되게 됩니다.

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

 

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

잉G님의 프로필

잉G

질문자

2023.12.21

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

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

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

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

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

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