코루틴의 이해

이윤설·2024년 10월 27일

코루틴 연구소

목록 보기
10/10

1. 루틴, 서브루틴, 코루틴

루틴

  • 루틴: 루틴이란, 특정한 일을 처리하기 위한 일련의 처리 과정
  • 프로그래밍에서의 루틴: 특정한 일을 처리하기 위한 일련의 처리 과정 == 함수(method)

서브루틴

  • 서브루틴: 함수 내에서 함수가 호출될 경우 호출된 함수를 '서브루틴'이라고 부른다.
    즉, 루틴에서 추가되는 실행되는 루틴이 서브루틴이다.


서브루틴은 한 번 실행되면 끝까지 실행된다.
또한 루틴에 의해 서브루틴이 호출되면, 루틴이 실행하던 스레드는 서브루틴을 실행하는 데에 사용돼 서브루틴의 실행이 완료될 때까지 다른 작업을 수행할 수 없다.

코루틴

루틴에 의해 서브 루틴이 호출되면 서브루틴의 실행이 완료될 때까지 다른 작업을 할 수 없는 것과 다르게 코루틴(Coroutine)은 함께(Co) 실행되는 루틴으로 서로 간에 스레드 사용을 양보하며 함께 실행된다.

비교

2. 코루틴의 스레드 양보

코루틴은 작업 중간에 스레드의 사용이 필요 없어지면 스레드를 양보한다. 이때 양보된 스레드는 다른 코루틴이 점유해 사용할 수 있다.
스레드를 양보하는 주체는 코루틴이다. 따라서 스레드를 양보하기 위해서는 코루틴이 직접 스레드 양보를 위한 함수를 호출해야 한다.

delay 함수로 알아보는 스레드 양보

작업을 일정 시간 동안 일시 중단해야 할 경우 delay 함수를 사용할 수 있다.
코루틴이 delay 함수를 호출하면 코루틴은 사용하던 스레드를 양보하고 설정된 시간 동안 일시 중단된다


모든 코루틴이 실행완료될 때까지 걸리는 시간은 1초 근방이다.
동일한 시간에 아주 빠른 속도로 delay 함수를 통해 스레드 양보가 이루어진다.


Thread.sleep을 사용하면 1초 동안 스레드 블로킹이 이루어진다.
즉, 코루틴의 스레드 점유는 유지된다. 그렇기 때문에 코루틴이 바뀌기까지 1초가 소요되는 것이다.

join과 await의 양보

Job의 join 함수나 Deferred의 await 함수가 호출되면, 해당 함수를 호출한 코루틴은 스레드를 양보하고, join 또는 await의 대상이 된 코루틴이 완료될 때까지 일시 중단된다.

하나의 코루틴이 스레드를 양보하지 않으면 다른 코루틴은 스레드를 점유하지 못한다.

yield 함수를 통해 양보하기

몇가지 상황에서는 yield 함수를 통해 직접 스레드를 양보하는 것이 필요하다.
특히, 단일 스레드만 사용하는 상황에서는 명시적으로 yield를 사용해야 하는 경우가 종종 생긴다.

언뜻 봐서는 1초 후에 작업이 중단될 것 같지만, 작업은 영원히 중단되지 않는다.
delay(100L) -> while문 실행 후 runBlocking 코루틴에게 양보해야 하는데, 그런 로직이 없다.


두 코드의 차이점은 코루틴이 실행되는 디스패처다.

첫 번째 코드: launchrunBlocking의 디스패처 사용

첫 번째 코드에서 launchrunBlocking의 디스패처를 사용하기 때문에 메인 스레드에서 실행된다. while 반복문이 메인 스레드를 계속 차지하고 있어, delaycancel 호출이 메인 스레드에 도달하지 못한다. 결국 job.cancel()이 호출되지 않아 isActive 체크가 계속 무한 반복된다.

두 번째 코드: Dispatchers.Default 사용

두 번째 코드에서는 Dispatchers.Default를 사용해 코루틴을 별도의 스레드 풀에서 실행한다.
이로 인해 while 반복문이 실행되는 동안에도 runBlockingdelaycancel 호출이 차단되지 않고, 코루틴이 정상적으로 취소된다.

3. 코루틴의 실행 스레드

코루틴의 실행 스레드는 고정이 아니다.

코루틴이 일시 중단된 후 재개되면 CoroutineDispatcher 객체는 재개된 코루틴을 다시 스레드에 보낸다. 이때 CoroutineDispatcher 객체는 코루틴을 사용할 수 있는 스레드 중 하나에 보내기 때문에, 코루틴이 재개된 후의 실행 스레드는 일시 중단되기 전의 스레드와 다를 수 있다.


예를 들어 원래 스레드1에서 실행하던 코루틴을 일시정지 할 때 코루틴2는 스레드1에 들어올 것이다.
일시정지가 풀리면 스레드1은 이미 가득 차있는 상태다. 따라서 빈 스레드인 스레드2로 이동할 수도 있다.

스레드를 양보하지 않으면 실행 스레드가 바뀌지 않는다.

"스레드를 양보하지 않으면 실행 스레드가 바뀌지 않는다"는 말은 현재 실행 중인 코드가 자리를 비켜주지 않으면, 다른 작업이 들어올 수 없다는 의미이다.

쉽게 말해, 내가 계속 말을 하면 다른 사람이 말을 할 기회가 없는 것과 같다.
프로그램도 마찬가지로, 현재 작업이 실행되는 스레드를 점유하고 있으면 다른 작업이 그 스레드에 들어올 수 없다

스레드를 양보하는 delay()를 사용하면 실행 스레드가 변경된다.
하지만 Thread.sleep은 실행 스레드가 변경되지 않음을 확인할 수 있다.


요약

루틴, 서브루틴, 코루틴

• 프로그래밍에서는 루틴을 ‘특정한 일을 하기 위한 일련의 명령‘ 이라는 의미로 사용하고, 이를 ‘함수’ 또는 ‘메서드’ 라고도 부른다.
• 함수(루틴) 내에서 함수가 호출될 경우 호출된 함수를 ‘서브루틴’이라고 부른다.
• 루틴에 의해 서브루틴이 호출되면 서브루틴의 실행이 완료될 때까지 다른 작업을 할 수 없는 것과 다르게
코루틴(Coroutine)은 함께(Co) 실행되는 루틴으로 서로 간에 스레드 사용을 양보하며 함께 실행된다.

코루틴의 스레드 양보

• 코루틴이 delay 함수를 호출하면 코루틴은 사용하던 스레드를 양보하고 설정된 시간 동안 일시 중단된다.
• Job의 join 함수나 Deferred의 await 함수가 호출되면 해당 함수를 호출한 코루틴은 스레드를 양보하고,
join 또는 await의 대상이 된 코루틴이 완료될 때까지 일시 중단된다.
• yield 함수는 스레드 사용 권한을 명시적으로 양보해야 할 때 사용된다.

코루틴의 실행 스레드

• 코루틴이 스레드를 양보하면 코루틴은 일시 중단되고, 이후 재개될 때 실행 스레드가 바뀔 수 있다.
• 코루틴이 스레드를 양보하지 않으면 실행 스레드가 바뀌지 않는다.


강의자료 출처 및 참고한 강의:

코틀린 코루틴 완전 정복 by 조세영님
https://www.inflearn.com/course/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EC%99%84%EC%A0%84-%EC%A0%95%EB%B3%B5/dashboard

profile
화려한 외면이 아닌 단단한 내면

0개의 댓글