Sobes.tech
Middle

Czym jest coroutine w Kotlin i jak działa?

sobes.tech AI

Odpowiedź od AI

Krotina w Kotlinie to lekka jednostka wykonawcza, która pozwala na pisanie kodu asynchronicznego i nieblokującego w bardziej czytelny i sekwencyjny sposób. Jest podobna do wątku (thread), ale znacznie lżejsza i może być tworzona w dużej ilości.

Główne komponenty i zasady działania:

  • Funkcje zawieszone (Suspend Functions): Funkcje oznaczone słowem kluczowym suspend, które mogą zawiesić swoje wykonanie bez blokowania wątku, na którym są wykonywane. Gdy zawieszona funkcja kończy operację "oczekiwania" (np. zapytanie sieciowe), może wznowić wykonanie od miejsca zawieszenia.
  • Kontekst (Kontekst korutyny): Zbiór elementów kontrolujących zachowanie korutyny. Wchodzi w skład:
    • Job: Deskryptor korutyny, umożliwiający zarządzanie jej cyklem życia (anulowanie, oczekiwanie na zakończenie).
    • CoroutineDispatcher: Określa wątek(-i), na którym(-ych) będzie wykonywana korutyna. Umożliwia przełączanie między wątkami.
    • CoroutineName: Opcjonalna nazwa do debugowania.
    • CoroutineExceptionHandler: Obsługa nieobsłużonych wyjątków.
  • Budowniczy (Builder): Funkcje uruchamiające wykonanie korutyn:
    • launch: Uruchamia nową korutynę, nie zwracając wyniku. Zwraca Job.
    • async: Uruchamia nową korutynę, zwracającą wynik (Deferred). Aby uzyskać wynik, używa się .await().
    • runBlocking: Budowniczy blokujący, używany głównie do testów lub integracji z blokującym kodem.

Jak to działa od kuchni:

Korutyny nie tworzą osobnych wątków dla każdego zadania. Zamiast tego, gdy funkcja suspend jest zawieszona, kompilator generuje kod, który zapisuje aktualny stan obliczeń. Gdy wynik jest dostępny, korutyna jest wznawiana na jednym z wątków zarządzanych przez CoroutineDispatcher. Jest to osiągane przez przekształcenie funkcji suspend w wywołania asynchroniczne z kontynuacjami, co pozwala jednemu wątkowi wykonywać wiele korutyn, przełączając się między nimi podczas zawieszenia.

Przykład:

import kotlinx.coroutines.*

fun main() = runBlocking { // Blokuje bieżący wątek do czasu zakończenia korutyny w runBlocking
    println("Najpierw")

    launch { // Uruchamia nową korutynę w tle
        delay(1000L) // Nieblokujące opóźnienie na 1 sekundę
        println("Po opóźnieniu")
    }

    println("Potem") // Ta linijka wykona się przed zakończeniem korutyny launch
}

Wynik tego kodu będzie:

Najpierw
Potem
Po opóźnieniu

To demonstruje nieblokujący charakter launch i delay.