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..
여러 비동기 함수에서 데이터를 동시에 얻어야 하는 경우를 생각해 보자. 코루틴 스코프 함수가 소개되기 전에 사용한 방법들 suspend fun getUserProfile(): UserProfileData { val user = getUserData() // 1초 후 val notifications = getNotifications() // 1초 후 return UserProfileData( user = user, notifications = notifications, )}먼저 중단 함수에서 중단 함수를 호출하는 방법이 있다. 하지만 이런 방식은 작업이 동시에 진행되지 않는다.하나의 함수에서 데이터를 얻는 데 1초씩 걸리기 때문에 총 2초가 걸린다. susp..
코루틴은 잡히지 않은 예외가 발생했을 때 종료된다스레드도 동일한 경우에 종료되지만, 차이점이 있다.코루틴 빌더는 부모도 종료시키고, 종료된 부모는 자식들까지 모두 취소시킨다는 것이다. fun main(): Unit = runBlocking { launch { launch { delay(1000) throw Error("Some error") } launch { delay(2000) println("Will not be printed") } launch { delay(500) println("W..
코루틴에서 아주 중요한 기능 중 하나는 바로 취소다.작업을 취소하기 위해 단순히 스레드를 죽이는 것은 최악의 방법이다. 연결을 닫고 자원을 해제할 방법이 없기 때문이다.개발자들이 상태가 Active한지 계속해서 확인하는 방법도 불편하다.코루틴의 취소 방식은 아주 간단하고 편리하며, 안전하다. 기본적인 취소Job 인터페이스는 잡을 취소하는 cancel() 함수를 가지고 있다. cancel() 함수를 호출하면 다음과 같은 효과가 일어난다.cancel()을 호출한 코루틴은 첫 번째 중단점에서 잡을 끝낸다.잡의 자식들도 취소된다. 하지만 잡의 부모는 영향을 받지 않는다.취소된 잡은 새로운 코루틴의 부모로 사용될 수 없다. 취소된 잡은 Cancelling 상태가 되었다가 Cancelled 상태가 된다. canc..