collect에서 데이터 발행과 소비가 일어나는 방식
flow의 collect를 사용하면 하나의 Coroutine에서 발행과 소비가 같이 일어나기 때문에 데이터가 발행된 후 소비가 끝나고 나서 다시 다음 데이터가 발행된다. 즉 발행과 소비가 순차적으로 일어난다. 이를 그림으로 표현하면 다음과 같다.
하지만 이 방식은 매우 비효율적이다. 발행하는 쪽이나 소비하는 쪽의 delay를 미리 처리하지 않는다면 발행부와 소비부 양쪽에서 모두 delay가 생기기 때문이다.
예를 들어 다음과 같이 발행에 1초 소비에 3초가 걸리는 코드가 있다고 해보자.
그림2의 로그에서 볼 수 있듯이 collect를 사용하면 데이터를 발행하는데 1초 소비하는데 3초가 걸려서 총 4초가 발행과 소비에 사용된다. 즉, 발행에 지연(delay)이 생긴다면 데이터를 늦게 발행 받아 소비에도 지연(delay)이 생기게된다. 따라서 데이터 발행과 소비가 순차적으로 일어나는 것은 비효율적이다.
우리는 이를 발행과 소비를 위한 Coroutine을 분리시키는 방식으로 해결할 수 있으며, 이를 위한 함수가 바로 buffer이다.
buffer을 이용한 최적화
그림2의 코드의 문제점은 데이터 발행과 소비가 순차적으로 일어난다는 점이었다. 이를 효율적으로 만들 수 있는 방법은 발행을 위한 Coroutine과 소비를 위한 Coroutine을 분리하는 것이다. 발행을 위한 Coroutine과 소비를 위한 Coroutine이 분리된다면 소비가 완료되었을 때 발행에 대한 delay없이 바로 바로 발행이 가능해지기 때문이다.
이것을 가능하게 만드는 것이 바로 buffer이다. buffer은 발행하는 쪽과 소비하는 쪽의 Coroutine을 분리하는 역할을 한다. 따라서 발행은 발행대로 일어나고 소비는 소비대로 일어나게 된다.
아래 그림4와 같이 buffer을 collect와 flow 중간에 사용해보자.
buffer가 사용되어 발행을 위한 Coroutine과 소비를 위한 Coroutine이 분리되었다. 이로 인해 발행쪽에서 발행(emit)은 별도의 Coroutine에서 수행되므로 계속해서 일어나고, 소비가 끝나는대로 바로바로 다음 데이터가 소비하는 쪽으로 전달되는 것을 확인할 수 있다. 이를 통해 발행에 생기는 지연을 방지할 수 있다.
*Coroutine은 일시 중단되었을 때 Thread를 blocking하지 않으므로 성능 면에서도 문제가 없다.
flow의 발행부과 소비부 양쪽에 지연이 생길 때는 buffer을 사용해 최적화 시키자.