출처: 조세영님의 인프런 강의, 코틀린 코루틴 강의 완전 정복
강의의 첫 번째 실습에서는 메인 스레드에서 새로운 스레드를 생성하여 멀티 스레딩 동작을 파악했다. 두 스레드의 동작을 출력하여 스레드의 시작과 끝 시점을 파악했다. 자바에서 자주 사용하는 방식의 코드를 실행한 후, 코틀린의 람다 형식으로 간단하게 변경했다.
그러나 Thread를 직접 생성하여 사용하는 방식에는 한계가 존재한다.
- Thread start를 호출할 때마다 새로운 스레드가 생성되고 재사용이 어렵다 (스레드는 비싼 자원이므로 치명적인 단점)
- 개발자가 스레드 생성과 관리에 대한 큰 책임을 진다 (실수나 오류로 메모리 누수 위험이 있고, 프로그램이 복잡해질수록 관리하기 어려움)
해당 문제를 해결하기 위한 방법으로 Executor 프레임워크가 등장했다. Executor의 역할은 다음과 같다.
1. 한 번 생성한 스레드를 쉽게 재사용 하기
2. 스레드 관리 책임을 시스템에 넘기기
=> 스레드 풀을 미리 만들어 놓고, 쉬고 있는 스레드에 작업을 분배한다.
=> 개발자의 책임은 스레드 풀 크기 관리와 작업 대기열에 작업을 submit 하는 것으로 대폭 줄어들었고, 스레드 재사용이 쉬워진다.
그러나 Executor 프레임워크의 한계로 "Thread Blocking" 문제가 생긴다. 이를 처리하기 위해 Callback 형식으로 문제를 해결하는 방식이 등장했으나, 콜백이 매우 많아질 때 복잡해지고(순차적인 처리 등) 예외 처리에 어려움이 생긴다.
RxJava를 통해 결과값을 데이터 스트림으로 처리하는 등의 보완 방법이 등장했으나 완벽한 해결은 아니다. 이는 두 가지 방식 모두, Thread 기반의 동작이기 때문이다.
+ 그렇다고 RxJava가 단점만 있는 것은 아니다. 종종 현업 안드로이드 직무 JD를 분석해보면 RxJava를 사용하는 곳도 많다. 기존 코드와의 호환성 문제 & RxJava만의 장점인 다양한 연산자를 통한 복잡한 스트림 처리나 이벤트 흐름 제어로 코루틴으로의 전환이 쉽지 않을 수 있다. 특히, 변환, 결합, 필터링 등의 연산자들이 매우 풍부하게 제공되어 복잡한 데이터 흐름을 다루기에 좋다고 한다.
Thread 기반 작업의 한계를 자세히 알아보자.
1. 스레드 기반 작업들은 작업의 전환이 어렵고, 전환에 드는 비용이 비싸다.
2. 간단한 작업에서는 Callback 방식이나 체이닝 함수 등을 사용하여 블로킹 문제를 해결하려고 한다.
But 실제 애플리케이션은 작업 간의 종속성이 복잡해 스레드 블로킹이 필연적으로 발생한다.
코루틴을 사용한 스레드 블로킹 문제 해결 방법
코루틴에서는 '코루틴' 이라고 불리는 작업 단위를 사용한다.
- 스레드에 붙였다가 뗐다가 하면서 유동적으로 사용할 수 있는 작업 단위이다.
- 코루틴은 스레드의 사용 권한을 양보할 수 있다.
- 중간에 작업을 중단하고 스레드 사용 권한을 반납하여 다른 코루틴이 실행될 수 있다.
- 즉, 원래라면 블로킹이 발생해야 하는 시간에 다른 코루틴이 실행되어 효과적인 동작이 가능해진다.
코루틴을 사용하면 좋은 동작들?
I/O 작업 (네트워크, DB 입출력)
반대로 코루틴을 사용해도 성능이 비슷한 작업도 있다.
CPU 바운드 작업
- 이미지, 동영상의 인코딩 or 디코딩
- 대용량 데이터 변환
코루틴은 경량화된 스레딩이라는 이점 외에도 다양한 장점이 있다. 비동기 프로그래밍의 안정성을 높이고 실행중인 스레드를 손쉽게 전환할 수 있게 만든다. 쉬운 예외 처리도 가능해진다.
'Coroutines' 카테고리의 다른 글
2. 코루틴 실행하기 (1) | 2024.10.10 |
---|