코루틴 채널 파트 4 – 버퍼링된 채널, 채널 평등, 티커 채널

버퍼 채널*1

지금까지 표시된 채널에는 버퍼가 없습니다.

버퍼링되지 않은 채널은 발신자와 수신자가 만날 때 값을 전송합니다.

이것은 랑데부 포인트라고도 합니다.

*2 만약에 보내다먼저 실행, 받다실행될 때까지 일시 중지됩니다.

만약에 받다먼저 실행, 보내다실행될 때까지 일시 중지됩니다.

Channel() 팩토리 함수와 프로덕션 빌더는 선택적으로 버퍼 크기를 사용하여 크기를 조정할 수 있습니다.

용량 파라미터를 받습니다.

BlockingQueue와 마찬가지로 Buffer는 용량버퍼가 가득 차면 발신자가 일시 중지*3 및 중지*4 전에 여러 요소를 보낼 수 있습니다.

다음 코드의 동작을 살펴보겠습니다.

val channel = Channel<Int>(4) // create buffered channel
val sender = launch { // launch sender coroutine
    repeat(10) {
        println("Sending $it") // print before sending each element
        channel.send(it) // will suspend when buffer is full
    }
}
// don't receive anything... just wait....
delay(1000)
sender.cancel() // cancel sender coroutine

전체 코드는 여기허용

이것은 용량4개의 Buffered Channel을 사용하므로 Sending은 5번 출력된다.

Sending 0
Sending 1
Sending 2
Sending 3
Sending 4

처음 4개의 요소가 버퍼에 추가되고 5번째를 보내려고 하면 발신자가 중단됩니다.


다음 내용은 독자의 이해를 위해 번역자가 추가한 내용입니다.

*하나. 버퍼는 첫 번째 입력이 대기 중인 동안 다음 입력이 저장되는 공간입니다.

버퍼링된 채널은 첫 번째 입력이 처리되지 않는 동안 보내기를 통해 수신된 다음 입력을 저장할 공간이 있는 채널입니다.

*2. 원문은 (일명 랑데부)인데, 이해를 돕기 위해 따로 번역했습니다.

랑데부(Rendezvous)는 프랑스어로 ‘만나다’라는 뜻이다.

*3. capacity=0이 기본값인데 들어오자마자 멈춘다.

*4. 원문은 블록이지만 채널이 일시적으로 정지되어 중단으로 번역됩니다.


이 문서는 공식 코루틴 문서를 번역한 것입니다.

원래: 채널 – 버퍼링된 채널

원본 최종 편집: 2022년 9월 28일


채널이 같음

채널에서 보내기 및 받기 작업은 여러 코루틴이 호출되는 순서에 따라 공정합니다.

채널은 FIFO 구조로 제공되며, 먼저 받다호출된 코루틴에는 하나의 요소가 있습니다.

다음 예제에서는 “ping” 및 “pong”이라는 두 개의 코루틴이 공유됩니다.

테이블 채널을 통해 “공” 개체를 받습니다.

data class Ball(var hits: Int)

fun main() = runBlocking {
    val table = Channel<Ball>() // a shared table
    launch { player("ping", table) }
    launch { player("pong", table) }
    table.send(Ball(0)) // serve the ball
    delay(1000) // delay 1 second
    coroutineContext.cancelChildren() // game over, cancel them
}

suspend fun player(name: String, table: Channel<Ball>) {
    for (ball in table) { // receive the ball in a loop
        ball.hits++
        println("$name $ball")
        delay(300) // wait a bit
        table.send(ball) // send the ball back
    }
}

전체 코드는 여기허용

“ping” 코루틴이 먼저 시작됩니다.

따라서 이 코루틴은 공을 먼저 받습니다.

“ping” 코루틴이 공을 다시 테이블로 보낸 후 즉시 다시 수신을 시작하더라도 “pong” 코루틴이 이미 듣고 있기 때문에 “pong” 코루틴이 공을 수신합니다.

ping Ball(hits=1)
pong Ball(hits=2)
ping Ball(hits=3)
pong Ball(hits=4)

간혹 사용하는 송신기의 특성상 채널이 정상적으로 동작하지 않을 수 있습니다.

자세한 내용은 이 문제보자. *하나


다음 내용은 독자의 이해를 위해 번역자가 추가한 내용입니다.

*하나. 이 문제는 실제로 자주 발생합니다.

이것은 하나의 스레드에서 여러 개의 코루틴을 실행할 때 문제가 되는 것 같습니다.

연산 중에 코루틴이 양보하면 스레드를 점유하고 있는 코루틴이 먼저 실행됩니다.

따라서 여러 개의 코루틴이 단일 스레드에서 실행되는 경우 채널에 대한 수신을 먼저 수행하는 사람은 무작위가 됩니다.

그 이유는 리시브를 통한 정지가 없기 때문입니다.


이 문서는 공식 코루틴 문서를 번역한 것입니다.

원래: 채널 – 코루틴 및 스레드 디버깅

원본 최종 편집: 2022년 9월 28일


스톡 채널

티커 채널은 채널이 마지막으로 사용된 후 일정 시간이 경과한 후 유닛을 생성하는 특별한 랑데뷰 채널입니다.

이것은 그 자체로는 쓸모가 없어 보일 수 있지만 복잡한 시간 기반 프로덕션 파이프라인 블록 또는 창*1 또는 시간 종속 처리를 구축하는 데 유용합니다.

코드 레인을 선택하여 “온 틱” 작업을 수행할 수 있습니다.

이 채널을 만드세요 증권 시세 표시기 더 이상 요소를 받을 필요가 없음을 나타내는 데 사용할 수 있는 ReceiveChannel.cancel이라는 메서드를 사용합니다.

실제로 어떻게 작동하는지 봅시다:

fun main() = runBlocking<Unit> {
    val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel
    var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
    println("Initial element is available immediately: $nextElement") // no initial delay

    nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements have 100ms delay
    println("Next element is not ready in 50 ms: $nextElement")

    nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
    println("Next element is ready in 100 ms: $nextElement")

    // Emulate large consumption delays
    println("Consumer pauses for 150ms")
    delay(150)
    // Next element is available immediately
    nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
    println("Next element is available immediately after large consumer delay: $nextElement")
    // Note that the pause between `receive` calls is taken into account and next element arrives faster
    nextElement = withTimeoutOrNull(60) { tickerChannel.receive() } 
    println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")

    tickerChannel.cancel() // indicate that no more elements are needed
}

전체 코드는 여기허용

그러면 다음 줄이 인쇄됩니다.

Initial element is available immediately: kotlin.Unit
Next element is not ready in 50 ms: null
Next element is ready in 100 ms: kotlin.Unit
Consumer pauses for 150ms
Next element is available immediately after large consumer delay: kotlin.Unit
Next element is ready in 50ms after consumer pause in 150ms: kotlin.Unit

티커는 소비자가 일시 중지하고 있음을 알고 있으며 기본 동작은 일시 중지가 발생할 때 다음 요소 생성을 지연하여 요소가 일정한 속도로 계속 생성

선택적 패턴 매개변수 TickerMode.FIXED_DELAY 두 요소 사이에 일정한 지연을 생성하도록 설정할 수 있습니다.


다음 내용은 독자의 이해를 위해 번역자가 추가한 내용입니다.

*하나. Windowing은 보낸 사람의 승인을 받지 않고 데이터를 계속 보내는 기술입니다.


이 문서는 공식 코루틴 문서를 번역한 것입니다.

원래: 채널 – 티커 채널

원본 최종 편집: 2022년 9월 28일