0Pricing
Kotlin Academy · Lekcja

Podstawy Channel: send, receive i close

Twórz kanały, wysyłaj i odbieraj wartości oraz poprawnie je zamykaj.

Podstawy Channel: send, receive i close to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Czym jest kanał?

Channel to prymityw korutynowy służący do komunikacji między korutynami — przypomina blokującą kolejkę, ale zamiast blokować, zawiesza wykonanie. Można myśleć o nim jak o rurze: jedna strona wysyła, a druga odbiera.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val channel = Channel<Int>()
    launch {
        for (i in 1..5) channel.send(i)
        channel.close()
    }
    for (x in channel) println(x) // 1 2 3 4 5
}

send i receive

send(value) zawiesza wykonanie do momentu, gdy odbiorca będzie gotowy. receive() zawiesza wykonanie do momentu, gdy wartość będzie dostępna.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<String>()
    launch {
        ch.send("ping")
        println("sent")
    }
    val msg = ch.receive()
    println("received: $msg")
}

Zamykanie kanału

channel.close() sygnalizuje, że nie zostaną wysłane już żadne wartości. Odbiorcy otrzymują pozostałe wartości z bufora, po czym pętla for się kończy.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<Int>(3)
    launch {
        repeat(3) { ch.send(it) }
        ch.close()  // signal done
    }
    for (v in ch) println(v) // 0 1 2, then loop ends
    println("Channel consumed")
}

isClosedForSend / isClosedForReceive

Stan kanału można sprawdzić za pomocą isClosedForSend (wysyłanie kolejnych wartości nie jest dozwolone) oraz isClosedForReceive (wszystkie wartości zostały odebrane).

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<Int>()
    launch {
        ch.send(1)
        ch.close()
    }
    println(ch.receive())
    println("isClosedForReceive: ${ch.isClosedForReceive}")
}

Konstruktor produce

produce { } to konstruktor korutyny, który tworzy korutynę producenta i zwraca ReceiveChannel. Kanał zamyka się automatycznie po zakończeniu bloku.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.squares(n: Int) = produce<Int> {
    for (i in 1..n) send(i * i)
}
fun main() = runBlocking {
    val sq = squares(5)
    for (v in sq) println(v) // 1 4 9 16 25
}

Rozszerzenie consumeEach

consumeEach { } iteruje po kanale i anuluje go, gdy blok zgłosi wyjątek, zapobiegając wyciekom zasobów.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = produce<String> {
        send("a"); send("b"); send("c")
    }
    ch.consumeEach { println(it) }
}

tryReceive i trySend

Wersje niewymagające zawieszenia: trySend / tryReceive natychmiast zwracają ChannelResult, nie zawieszając wykonania.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<Int>(1)
    val sendResult = ch.trySend(42)
    println("Sent: ${sendResult.isSuccess}")
    val recvResult = ch.tryReceive()
    println("Got: ${recvResult.getOrNull()}")
}

Rozdzielanie: wielu konsumentów

Wiele korutyn może odbierać dane z tego samego kanału, rozdzielając między siebie pracę — jest to wzorzec fan-out.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val tasks = produce { repeat(6) { send(it) } }
    repeat(3) { worker ->
        launch {
            for (task in tasks) {
                println("Worker $worker: task $task")
            }
        }
    }
}

Scalanie: wielu producentów

Wiele korutyn może wysyłać dane do tego samego kanału, łącząc swoje wyniki — jest to wzorzec fan-in.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val results = Channel<String>()
    repeat(3) { i ->
        launch { results.send("result-$i") }
    }
    launch {
        repeat(3) { println(results.receive()) }
        results.close()
    }
}

Wzorzec potoku

Należy połączyć kanały w potok, w którym każdy etap odczytuje dane z jednego kanału i zapisuje je do kolejnego — doskonale sprawdza się to w potokach przetwarzania danych.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.numbers() = produce { for (i in 1..5) send(i) }
fun CoroutineScope.doubled(input: ReceiveChannel<Int>) = produce { for (v in input) send(v * 2) }
fun main() = runBlocking {
    val nums = numbers()
    val doubled = doubled(nums)
    for (v in doubled) println(v) // 2 4 6 8 10
    coroutineContext.cancelChildren()
}

Kanał a Flow

Kanały są gorące i stanowe — istnieją niezależnie od odbioru danych. Przepływy są zimne i deklaratywne — uruchamiają się ponownie przy każdym zbieraniu. Należy preferować Flow dla strumieni danych, a Channel stosować do komunikacji producent–konsument.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.flow.*
// Flow (cold): each collect() re-runs the block
// Channel (hot): shared; multiple receivers share the same stream
fun main() = runBlocking { println("Flow = cold; Channel = hot") }

Szybkie sprawdzenie

Co się dzieje po wywołaniu channel.close()?

Podsumowanie

send i receive zawieszają wykonanie do momentu, gdy druga strona będzie gotowa. close() sygnalizuje zakończenie. Należy używać produce dla producentów zamykających się automatycznie, consumeEach do bezpiecznej iteracji, a kanałów dla wzorców fan-out/fan-in.

Często zadawane pytania

Czy lekcja „Podstawy Channel: send, receive i close” jest bezpłatna?

Tak — pełny tekst „Podstawy Channel: send, receive i close” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Podstawy Channel: send, receive i close”?

Twórz kanały, wysyłaj i odbieraj wartości oraz poprawnie je zamykaj. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Podstawy Channel: send, receive i close”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy Channel: send, receive i close
  2. Typy Channel: Rendezvous, Buffered, Conflated, Unlimited
  3. Mutex i Semaphore dla współdzielonego stanu
  4. Aktory i strukturalne zarządzanie stanem
← Powrót do Kotlin Academy