우리가 사용하는 대부분의 데이터 소스는 핫 스트림 데이터와 콜드 스트림 데이터 두 가지로 구분할 수 있다.즉, 이 두 가지의 차이를 이해하는 것이 중요하다.핫콜드컬렉션(List, Set)Sequence, StreamChannelFLow, Rx.Java 스트림(List, Set과 같은) 컬렉션은 핫이고, Sequence와 자바의 Stream은 콜드다.Channel은 핫이고, Flow와 (Observable, Single과 같은) Rxlava 스트림은 콜드다. 핫 vs 콜드핫 데이터 스트림은 열정적이라 데이터를 소비하는 것과 무관하게 원소를 생성한다.반면에 콜드 데이터 스트림은 게을러서 요청이 있을 때만 작업을 수행하며, 아무것도 저장하지 않는다. fun main() { val l = buildLis..
코루틴에는 select 함수가 있다. 이 select 함수는 가장 먼저 완료되는 코루틴의 결과를 기다리는 역할을 한다.또한 여러 개의 채널 중 남은 공간이 있는 채널에 데이터를 보내거나, 여러 개의 채널 중 원소가 존재하는 채널로부터 원소를 받을 수도 있다.코루틴 사이에 경합을 일으키거나, 여러 개의 데이터 소스로부터 나오는 결괏값을 합칠 수도 있다. select 함수는 코틀린 코루틴이 출시된 이후부터 사용이 가능했지만, 아직 실험용이다. 즉, API 형태가 바뀔 가능성이 있다.select를 실제로 사용하는 경우가 드물기 때문에, 안정화될 가능성도 적다. 지연되는 값 선택하기여러 개의 소스에 데이터를 요청한 뒤, 가장 빠른 응답만 얻는 경우를 생각해 보자.가장 쉬운 방법은 요청을 여러 개의 비동기 프..

채널은 코루틴끼리의 통신하기 위한 기본적인 방법이다.채널은 공공 도서관으로 비유할 수 있다. 하나의 책을 찾으려면, 책을 빌렸던 사람이 다시 반납해야 한다.이는 채널이 작동하는 방식과 비슷하다.채널은 송신자와 수신자의 수에 제한이 없고, 채널을 통해 전송된 모든 값은 단 한 번만 받을 수 있다. interface SendChannel { suspend fun send(element: E) fun close(): Boolean // ...}interface ReceiveChannel { suspend fun receive(): E fun cancel(cause: CancellationException? = null) // ...}interface Channel : SendC..
UnconfinedTestDispatcherfun main() { CoroutineScope(StandardTestDispatcher()).launch { print("A") delay(1) print("B") } CoroutineScope(UnconfinedTestDispatcher()).launch { print("C") delay(1) print("D") }}C테스트 디스패처는 StandardTestDispatcher 외에 UnconfinedTestDispatcher도 있다. StandardTestDispatcher는 스케줄러를 사용하기 전까지 어떤 연산도 수행하지 않는다.반면에 UnconfinedTes..

더보기class FetchUserUseCase( private val repo: UserDataRepository,) { suspend fun fetchUserData(): User = coroutineScope { val name = async { repo.getName() } val friends = async { repo.getFriends() } val profile = async { repo.getProfile() } User( name 三 name.await(), friends = friends.await(), profile = profile.await(), ) ..
class UserDownloader( private val api: NetworkService,) { private val users = mutableListOf() fun downloaded(): List = users.toList() suspend fun fetchUser(id: Int) { val newUser = api.fetchUser(id) users.add(newUser) }}시작하기 전에 위 코드를 살펴보자.이 클래스는 두 개 이상의 스레드가 동시에 사용할 경우에 대한 대비가 되어있지 않다.fetchUser()에서 users를 변경하고 있기 때문에, users는 공유 상태에 해당한다.따라서 users는 보호되어야 한다.두 개 이상의 스레..
이전 포스팅에서 코루틴 스코프를 적절하게 만드는 방법에 대해 배웠다.이번에는 스코프에 대해 배운 것들을 요약해 보고 일반적으로 사용하는 예시 상황에 대해 알아보자. CoroutineScope 팩토리 함수interface CoroutineScope { val coroutineContext: CoroutineContext}CoroutineScope는 coroutineContext를 유일한 프로퍼티로 가지고 있는 인터페이스이다. class SomeClass : CoroutineScope { override val coroutineContext: CoroutineContext = Job() fun onStart() { launch { // ... } ..

코루틴에서는 디스패처를 통해 코루틴이 실행되어야 할 스레드(또는 스레드 풀)를 결정한다.영어 사전에서 디스패처는 '사람이나 긴급 차량을 필요한 곳에 보내는 사람'이라 정의한다. 기본 디스패처디스패처를 설정하지 않으면 Dispatchers.Default가 기본적으로 설정된다.Dispatchers.Default는 프로그램이 실행되는 컴퓨터의 CPU 개수와 동일한 수(최소 두 개 이상)의 스레드 풀을 가지고 있다.이는 스레드를 효율적으로 사용한다고 가정했을 때, 이론적으로 가장 최적의 스레드 수다.따라서 Dispatchers.Default는 CPU 집약적인 연산을 수행하기에 적합하다. suspend fun main() = coroutineScope { repeat(1000) { launch..