Coroutine builder
코루틴 빌더에 원하는 동작을 람다로 넘긴 후 → 코루틴을 만들어 실행한다.
🙉 Job , Defferd<T> 는 뭐지?
코루틴 작업을 다루는 객체 (오브젝트)
- Job, Defferd<T>에 대해 취소나 예외처리를 함으로써 용이하게 코루틴의 흐름제어를 할 수 있게 된다.
- Deferred<T> 인터페이스는 Job인터페이스를 상속 받는다.
더 자세한 내용은 이전글을 참고해주세요!
2022.02.06 - [Platform/Android] - [Coroutine] Coroutine Context: 코루틴이 실행되는 곳
🙉 SendChannel<E>, ReceiveChannel<E> 는 뭐지?
둘 다 Channel!
- stream을 반환한다.
- FIFO 방식의 queue로 되어 있다.
- 더 이상 사용하지 않을때 close 할 수 있다.
- close는 특별한 token의 형태 → 이 값도 channel에 들어간다. → 따라서 iterator들은 이 값을 만나면(receive) iteration을 멈춥니다.
- 이런 형태이기 때문에 close를 호출하더라도 그 이전에 넣어놓은 값들을 받아올 수 있음을 보장한다.
따라서, 동시성이 필요한 여러 Coroutine 에서 순서를 보장 받으면서 공유하여 사용할 수 있다!
더 자세한 내용은 아래 블로그를 참고해주세요!
launch
현재 스레드를 Blocking 하지 않고, 새로운 코루틴을 실행한다.
- Job 으로 반환한다. 즉, 리턴 값이 없는 코루틴을 위해 사용한다.
- CoroutineScope 의 확장함수
- API
public fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext,//CoroutineContext 기본 start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job
-
더보기
public fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { val newContext =newCoroutineContext(context) val coroutine = if (start.isLazy) LazyStandaloneCoroutine(newContext, block) else StandaloneCoroutine(newContext, active = true) coroutine.start(start, coroutine, block) return coroutine }
async
현재 스레드를 Blocking 하지 않고, 새로운 코루틴을 실행한다.
- Deffered<T>로 반환한다. 즉, 리턴 값이 있는 코루틴을 위해 사용한다.
- 결과값을 반환 받고 싶은 경우, Aysnc Builder를 사용한다. - await()
- CoroutineScope 의 확장함수
- API
public fun <T> CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T>
-
더보기
public fun <T> CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T> { val newContext = newCoroutineContext(context) val coroutine = if (start.isLazy) LazyDeferredCoroutine(newContext, block) else DeferredCoroutine<T>(newContext, active = true) coroutine.start(start, coroutine, block) return coroutine }
withContext
부모 코루틴에 사용되던 context 와 다른 context 에서 코루틴을 실행시킬 수 있다. (Dispatchers이용)
- T를 반환한다.
- 결과 리턴이 나올때까지 대기한다.(이 자체로 정지 함수이다.)
- 마지막 줄의 값이 반환값이 된다.
- 비동기 작업을 순차 코드처럼 작성할 수 있게 된다.
- API
public suspend fun <T> withContext( context: CoroutineContext, block: suspend CoroutineScope.() -> T ): T
- 예제
-
val scope = CoroutineScope(Dispatchers.Main) fun login()= scope.launch { view.showLoading() withContext(Dispatcher.IO) { networkClient.login(...)} view.hideLoading() }
runBlocking
현재 스레드를 Blocking 하고, 새로운 코루틴을 실행한다.
- T를 반환한다.
- 사용하지 말라고 권장한다. → 특히, 안드로이드에서는 ANR 이 발생할 위험이 있다!
- 코드 테스트, 레거시 코드, 라이브러리 통합 시에만 사용하는 것이 좋다.
- API
-
public fun <T> runBlocking( context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T
- 예제
-
fun runBlockingExample() { runBlocking { //일반함수 launch { //CoroutineScope 의 확장함수 log("GlobalScope.launch started") } } }
fun main() { log("main() started") runBlockingExample() log("runBlockingExample() executed") log("main() terminated") }
-
더보기
결과
22:26:31.361 : Thread[main,5,main] : main() started 22:26:31.448 : Thread[main,5,main] : GlobalScope.launch started 22:26:31.448 : Thread[main,5,**main**] : runBlockingExample() executed 22:26:31.448 : Thread[main,5,main] : main() terminated #일시정지 없음
actor
Channel을 통해 코루틴 블럭(Scope)와 외부에서 통신을 통해 전송, 처리의 루틴을 실행한다.
- SendChannel<E> 를 반환한다.
- 해당 코루틴을 사용하는 곳에서 send(E) 형태로 E (메시지) 를 보내면
- 해당 코루틴에서 channel 내 메시지 E 로 받을 수 있다.
- actor{ } 블록 내부는 수신자(Receiver)가 되고 / 반환된 SendChannel이 송신자(Sender)가 된다.
- 상태 엑세스를 단일 thread로 한정한다. / 다른 thread는 채널을 통해서 상태 수정을 요청한다.
- 동기화 이슈가 있는 자원을 actor 내에서 관리하도록 한다.
- API
-
public fun <E> CoroutineScope.actor( context: CoroutineContext = EmptyCoroutineContext, capacity: Int = 0, // todo: Maybe Channel.DEFAULT here? start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend ActorScope<E>.() -> Unit ): SendChannel<E>
-
더보기
public fun <E> CoroutineScope.actor( context: CoroutineContext = EmptyCoroutineContext, capacity: Int = 0, // todo: Maybe Channel.DEFAULT here? start: CoroutineStart = CoroutineStart.DEFAULT, onCompletion: CompletionHandler? = null, block: suspend ActorScope<E>.() -> Unit ): SendChannel<E>
produce
Channel을 통해 코루틴 블럭(Scope)와 외부에서 통신을 통해 전송, 처리의 루틴을 실행한다.
- ReceiveChannel<E>를 반환한다.
- produce{ } 블록 내부는 송신자(Sender)가 되고, 반환된 ReceiveChannel이 수신자(Receiver).
- producer 는 값이 생성된 후 일시 중단되며, 새로운 값이 요청될 때 다시 재개한다. (시퀀스, 이터레이터와 유사)
- 특정 Coroutine Scope 로 생성할 수 있다.
- 전달되는 람다는 언제든지 일시 중단될 수 있다.
- Channel을 사용해 작동 → 데이터를 스트림처럼 생각할 수 있다. 요소를 수신하면 스트림에서 요소가 제거된다.
- API
-
public fun <E> CoroutineScope.produce( context: CoroutineContext = EmptyCoroutineContext, capacity: Int = 0, @BuilderInference block: suspend ProducerScope<E>.() -> Unit ): ReceiveChannel<E>
-
더보기
public fun <E> CoroutineScope.produce( context: CoroutineContext = EmptyCoroutineContext, capacity: Int = 0, @BuilderInference block: suspend ProducerScope<E>.() -> Unit ): ReceiveChannel<E> { val channel = Channel<E>(capacity) val newContext = newCoroutineContext(context) val coroutine = ProducerCoroutine(newContext, channel) coroutine.start(CoroutineStart.DEFAULT, coroutine, block) return coroutine }
- 예제
-
fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce { for (x in 1..5) send(x * x) } runBlocking { val squares = produceSquares() squares.consumeEach { log("📗","consumeEach, $it") } log("📙", "Done!") }
-
더보기
결과
.참고
https://tourspace.tistory.com/156?category=797357
https://myungpyo.medium.com/코루틴-공식-가이드-자세히-읽기-part-8-1b434772a100
'Language > Kotlin' 카테고리의 다른 글
[keyword] Companion Object (0) | 2022.02.17 |
---|---|
[Coroutine] suspending method: 코루틴 일시 중단 (0) | 2022.02.09 |
[Coroutine] Coroutine Context: 코루틴이 실행되는 곳 (0) | 2022.02.06 |
[Coroutine] Coroutine Scope: 코루틴이 실행되는 범위 (0) | 2022.02.05 |
[Coroutine] 코루틴 사용하기 (0) | 2022.02.05 |