목록Book/Kotlin Coroutines Deep Dive (21)
시배's Android
21장 플로우 만들기 원시값을 가지는 플로우 flowOf를 활용해 간단하게 플로우를 만들 수 있다. flowOf(1, 2, 3, 4,5 ).colect { // TODO } 값이 없는 플로우면 emptyFlow의 형태로 제공 컨버터 asFlow를 활용해 다음과 같은 타입을 플로우로 바꿀 수 있다. Iterable Iterator Sequence Mono Flux List 등등 함수를 플로우로 선언하기 함수가 플로우를 반환하도록 할 수 있다. fun someFunction(): Flow = flow { // Do Something emit(2) } 플로우와 리액티브 스트림 Flux, Mono또한 라이브러리에서 플로우의 변환을 제공한다. kotlinx-coroutines-reactor라이브러리를 활용하라 채..
20장 플로우의 실제 구현 플로우의 내부구현에 대해 알아보자. Flow 이해하기 간단한 람다식 @Test fun main() = runTest { val f: () -> Unit = { println("A") println("B") println("C") } f() } // 출력 겨로가 A B C 플로우는 위의 람다식과 별반 다를것이 없다. 아래는 실제 플로우의 내부 구현을 간단하게 구현해본 것이다. @Test fun main() = runTest { val f: suspend ((String) -> Unit) -> Unit = { emit -> emit("A") emit("B") emit("C") } f { println(it) } f { println(it) } } // 출력 결과 A B C A B ..
플로우는 비동기적으로 계산해야 할 값의 스트림을 나타냅니다. Flow 인터페이스 자체는 떠다니는 원소들을 모으는 역할을 하며, 플로우의 끝에 도달할 때까지 각 값을 처리하는 걸 의미합니다. 플로우를 사용하면 코루틴이 연산을 수행하는 데 필요한 기능을 전부 사용할 수 있습니다. 플로우의 빌더와 연산은 중단 함수이며 구조화된 동시성과 적절한 예외 처리를 지원합니다. 플로우는 어딘가에서 시작되어야 합니다. 플로우 빌더, 다른 객체에서의 변환, 또는 헬퍼 함수로부터 시작됩니다. 플로우의 마지막 연산은 최종 연산이라 불리며, 중단 가능하거나 스코프를 필요로 하는 유일한 연산이라는 점에서 아주 중요합니다. 시작 연산과 최종 연산 사이에 플로우를 변경하는 중간 연산을 가질 수 있습니다. 웹소켓이나 RSocket 알림..
핫 데이터 스트림은 열정적이라 데이터를 소비하는 것과 무관하게 원소를 생성하지만, 콜드 데이터 스트림은 게을러서 요청이 있을때만 작업을 수행하며 아무것도 저장하지 않습니다. 핫인 리스트와 콜드인 시퀀스를 사용할 때 그 차이가 드러납니다. 핫 데이터 스트림의 빌더와 연산은 즉각 실행됩니다. 콜드 데이터 스트림에서는 원소가 필요할 때까지 실행되지 않습니다. 콜드 데이터 스트림 무한할 수 있습니다. 최소한의 연산만 수행합니다. 메모리를 적게 사용합니다. 핫 데이터 스트림 항상 사용 가능한 상태입니다. 여러 번 사용되었을 때 매번 결과를 다시 계산할 필요가 없습니다. 채널은 핫이라 값을 곧바로 계산합니다. 별도의 코루틴에서 계산을 수행합니다. 채널은 소비되는 것과 상관없이 값을 생성한 뒤에 가지게 됩니다. 채널..
코루틴은 가장 먼저 완료되는 코루틴의 결과를 기다리는 select 함수를 제공합니다. 또한 여러 개의 채널 중 버퍼에 남은 공간이 있는 채널을 먼저 확인하여 데이터를 보내거나, 이용 가능한 원소가 있는 채널로부터 데이터를 받을 수 있는지 여부도 확인할 수 있습니다. 코루틴 사이에 경합을 일으키거나, 여러 개의 데이터 소스로부터 나오는 결과값을 합칠 수도 있습니다. 지연되는 값 선택하기 여러 개의 소스에 데이터를 요청한 뒤, 가장 빠른 응답만 얻는 경우를 생각해봅시다. 요청을 여러 개의 비동기 프로세스로 시작한 뒤, select 함수를 표현식으로 사용하고 표현식 내부에서 값을 기다리는 것입니다. select 내부에서는 셀렉트 표현식에서 나올 수 있는 결괏값을 명시하는 Deferred 값의 onAwait 함..
채널은 송신자와 수신자의 수에 제한이 없으며, 채널을 통해 전송된 모든 값은 단 한 번만 받을 수 있습니다. Channel은 두 개의 서로 다른 인터페이스를 구현한 하나의 인터페이스입니다. SendChannel은 원소를 보내거나 채널을 닫는 용도로 사용됩니다. ReceiveChannel은 원소를 받을 때 사용됩니다. 채널의 진입점을 제한하기 위해 ReceiveChannel이나 SendChannel 중 하나만 노출시키는 것도 가능합니다. receive를 호출했는데 채널에 원소가 없다면 코루틴은 원소가 들어올 때 까지 중단됩니다. 반면 send는 채널의 용량이 다 찼을 때 중단됩니다. 용량이 제한적인 채널에서만 trySend tryReceive를 사용해야 합니다. produce 함수는 빌도로 시작된 코루틴이..
TestCoroutineScheduler와 StandardTestDispatcher TestCoroutineScheduler는 delay를 가상 시간 동안 실행하여 실제 시간이 흘러간 상황과 동일하게 작동하기 때문에 정해진 시간만큼 기다리지 않도록 변경할 수 있습니다. 코루틴에서 TestCoroutineScheduler를 사용하려면, 이를 지원하는 디스패처를 사용해야 합니다. 일반적으로 StandardTestDispatcher를 사용합니다. 테스트 디스패처로 시작된 코루틴은 가상 시간만큼 진행되기 전까지 실행되지 않습니다. StandardTestDispatcher는 TestCoroutineScheduler를 만들기 때문에 명시적으로 만들지 않아도 됩니다. StandardTestDispatcher는 직접 ..
동기화 블로킹 자바에서 사용되는 전통적인 도구인 synchronized 블록이나 동기화된 컬렉션을 사용해 해결할 수 있습니다. 가장 큰 문제점은 synchronized 블록 내부에서 중단 함수를 사용할 수 없다는 것입니다. synchronized 블록에서 코루틴이 자기 차례를 기다릴 때 스레드를 블로킹한다는 것입니다. 원자성 자바는 다양한 원자값을 가지고 있습니다. 원자값을 활용한 연산은 빠르며 스레드 안전을 보장합니다. 원자성은 하나의 primitive 변수 또는 하나의 reference의 안전을 보장하기 위해 사용되지만, 좀 더 복잡한 경우에는 다른 방법을 사용해야 합니다. 싱글스레드로 제한된 디스패처 싱글스레드 디스패처를 사용하는 것이 공유 상태와 관련된 대부분의 문제를 해결하는 가장 쉬운 방법입니..