Coroutine Channels 2편 - Channel로 파이프라인 만들기, 파이프라인으로 소수 만들기

2023. 3. 6. 23:22·공식 문서 번역/Coroutines 공식 문서
반응형

Channel로 파이프라인 만들기

파이프라인은 하나의 Coroutine이 값의 스트림을 생성하는 것을 뜻한다. 값의 스트림은 무한할 수도 있다.

fun CoroutineScope.produceNumbers() = produce<Int> {
    var x = 1
    while (true) send(x++) // infinite stream of integers starting from 1
}

 

 

그리고 다른 Coroutine이나 Coroutines 들이 그 스트림을 소비하고, 작업을 수행하고, 다른 결과를 생성한다. 아래의 예시에서 숫자들은 단순히 제곱된다.

fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
    for (x in numbers) send(x * x)
}

 

메인 코드는 모든 파이프라인을 연결하기 시작한다.

val numbers = produceNumbers() // produces integers from 1 and on
val squares = square(numbers) // squares integers
repeat(5) {
    println(squares.receive()) // print first five
}
println("Done!") // we are done
coroutineContext.cancelChildren() // cancel children coroutines

📌 전체 코드는 이곳에서 확인할 수 있습니다.

 

📖  Coroutine을 생성하는 모든 함수들은 CoroutineScope의 확장함수로 정의되어 있다. 이를 통해 구조화된 동시성의 원칙에 의존하도록 해서 어플리케이션에 글로벌하게 남아있는 코루틴이 없도록 할 수 있다.*1

 

 


📖 아래 내용은 독자의 이해를 위해 번역자가 추가한 글입니다.

*1. 위 코드에서 produce { ... } 내부를 보면 다음과 같이 CoroutineScope의 확장함수로 선언되어 있다.

public fun <E> CoroutineScope.produce(
    context: CoroutineContext = EmptyCoroutineContext,
    capacity: Int = 0,
    @BuilderInference block: suspend ProducerScope<E>.() -> Unit
): ReceiveChannel<E> =
    produce(context, capacity, BufferOverflow.SUSPEND, CoroutineStart.DEFAULT, onCompletion = null, block = block)

이 글은 Coroutines 공식 문서를 번역한 글입니다.

 

원문 : Channels - Pipelines

원문 최종 수정 :  2022년 9월 28일

 


파이프라인으로 소수 만들기

Coroutine의 파이프라인을 사용해서 소수를 생성하는 예제를 통해 파이프라인을 극한으로 사용해보겠다. 숫자의 무한한 시퀀스로 시작해보자 :

fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
    var x = start
    while (true) send(x++) // infinite stream of integers from start
}

 

다음 파이프라인 단계에서는 들어오는 숫자의 스트림을 필터링해서, 주어진 소수로 나눌 수 있는 모든 숫자들을 제거한다.

fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
    for (x in numbers) if (x % prime != 0) send(x)
}

 

이제 숫자 스트림을 2에서 부터 시작하고, 현재 Channel에서 소수를 가져오고, 각 발견된 소수에 대해 새로운 파이프라인 단계를 실행하는 새로운 파이프라인을 구축한다.

numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...

 

다음 예제는 메인 스레드의 Context에서 모든 파이프라인을 실행해서, 첫 10개의 소수를 출력한다. Scope 내의 모든 Coroutine이 main 함수의 runBlocking Coroutine에서 실행되었으므로 시작한 코루틴들의 명시적인 리스트를 가지고 있을 필요가 없다. 처음 10개의 소수를 출력한 후, cancelChildren 확장 함수를 이용해서 모든 자식 Coroutine을 취소한다.

var cur = numbersFrom(2)
repeat(10) {
    val prime = cur.receive()
    println(prime)
    cur = filter(cur, prime)
}
coroutineContext.cancelChildren() // cancel all children to let main finish

📌 전체 코드는 이곳에서 확인할 수 있습니다.

 

코드의 출력은 다음과 같다 :

2
3
5
7
11
13
17
19
23
29

 

표준 라이브러리의 iterator Coroutine 빌더를 사용해 같은 파이프라인을 빌드할 수 있다. produce를 iterator로 send를 yield로, receive를 next로, ReceiveChannel을 Iterator로 바꾸고 Coroutine Scope을 제거하자. runBlocking 또한 필요 없어졌다. 하지만, 위에서 다룬 채널을 사용하는 파이프라인의 이점은 Dispatcher.Default Context 상에서 실행할 경우 복수의 CPU 코어를 사용할 수 있다는 점이다.

 

어쨌든, 이것은 소수를 찾는 매우 비현실적인 방법이다. 실제로 파이프라인은 다른 원격 서비스에 대한 비동기 호출과 같은 일시중단 호출이 포함되며, 이 파이프라인은 sequence / iterator 을 사용해서 만들어질 수 없다. 완전히 비동기적인 produce와 달리 임의의 일시 중단을 포함할 수 없기 때문이다.

 

 

 


이 글은 Coroutines 공식 문서를 번역한 글입니다.

 

원문 : Channels - Prime numbers with pipeline

원문 최종 수정 :  2022년 9월 28일

 


목차로 돌아가기

 

Kotlin Coroutines 공식 문서 한국어 번역본 : Coroutines 한 번에 정리하기

Kotlin Coroutines 공식 문서 번역을 시작하며 Kotlin Coroutines는 Kotlin을 위한 강력한 비동기 솔루션이다. 안드로이드 실무에서는 한동안 높은 점유율을 자랑한 RxJava를 Coroutines가 대체하고 있으며, 새로

simplecode.kr

 

반응형

'공식 문서 번역 > Coroutines 공식 문서' 카테고리의 다른 글

Coroutine Channels 4편 - Buffered channels, Channel은 평등하다, Ticker channels  (0) 2023.03.08
Coroutine Channels 3편 - Fan-out과 Fan-in : Channel이 얼마나 많은 출력, 입력을 만들 수 있는지 알아보기  (0) 2023.03.07
Coroutine Channels 1편 - Channel이란 무엇인가, Channel 닫기, Channel 반복적으로 수신하기, Producer로 Channel 만들기  (0) 2023.03.05
Coroutines Flow 8편 - Flow 실행하기, Flow와 Reactive Stream  (0) 2023.03.04
Coroutines Flow 7편 - Flow 수집 완료 처리하기, Flow 명령적으로 다루기 vs 선언적으로 다루기  (0) 2023.03.03


'공식 문서 번역/Coroutines 공식 문서' 카테고리의 다른 글
  • Coroutine Channels 4편 - Buffered channels, Channel은 평등하다, Ticker channels
  • Coroutine Channels 3편 - Fan-out과 Fan-in : Channel이 얼마나 많은 출력, 입력을 만들 수 있는지 알아보기
  • Coroutine Channels 1편 - Channel이란 무엇인가, Channel 닫기, Channel 반복적으로 수신하기, Producer로 Channel 만들기
  • Coroutines Flow 8편 - Flow 실행하기, Flow와 Reactive Stream
심플코드
심플코드
프로그래밍을 어렵지 않게 풀어서 설명하는 기술 블로그
    반응형
  • 심플코드
    심플코드
    심플코드
  • 전체
    오늘
    어제
    • 분류 전체보기 (96)
      • 안드로이드를 위한 Coroutines (2)
      • Unit Testing (19)
      • GitHub Actions (0)
      • 공식 문서 번역 (35)
        • Coroutines 공식 문서 (35)
      • 알고리즘 (7)
        • Kotlin 자료구조 (0)
        • 알고리즘 (7)
        • Kotlin으로 구현하는 자료구조 (0)
      • 코딩 테스트 (0)
      • Deep Learning (0)
      • Machine Learning Math (17)
        • Linear Algebra (17)
      • ML (0)
      • Docker (15)
      • Kubernetes (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 코틀린 코루틴의 정석 책 출간 소식
  • 인기 글

  • 태그

    TensorFlow
    코루틴 Flow
    pytorch
    coroutine
    Machine Learning
    Docker
    Coroutines Channel
    컨테이너
    Kotlin
    코루틴
    Coroutines Context
    mockito
    코루틴 채널
    junit
    unit testing
    Coroutines Flow
    numpy
    unit test
    Coroutines
    도커
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
심플코드
Coroutine Channels 2편 - Channel로 파이프라인 만들기, 파이프라인으로 소수 만들기
상단으로

티스토리툴바