Sobes.tech
Middle

Jaké možnosti nabízí Kotlin pro práci s asynchronními operacemi?

sobes.tech AI

Odpověď od AI

Kotlin poskytuje korutiny (coroutines) pro zjednodušení asynchronních operací a nabízí lehké proudy, které nezablokují hlavní vlákno provádění.

Hlavní možnosti:

  • Funkce pozastavení: Funkce označené klíčovým slovem suspend, které lze pozastavit a pokračovat. Neblokují vlákno, ve kterém jsou prováděny.
    suspend fun fetchData(): String {
        delay(1000) // Napodobujeme dlouhou operaci
        return "Data získána"
    }
    
  • Stavitelé korutin: Funkce používané k spuštění korutin:
    • launch: Spustí novou korutinu a vrátí Job (neblokující).
      GlobalScope.launch {
          println("Korutina spuštěna")
      }
      
    • async: Spustí novou korutinu a vrátí Deferred<T> (blokující při volání .await()).
      val deferred = GlobalScope.async {
          fetchData()
      }
      // ...
      val result = deferred.await() // Čeká na výsledek
      
    • runBlocking: Blokuje aktuální vlákno do dokončení korutiny (používá se hlavně jako most mezi blokujícím a neblokujícím kódem, například v testech).
      runBlocking {
          val data = fetchData()
          println(data)
      }
      
  • CoroutineContext: Sada prvků určujících chování korutiny, včetně Dispatcher a Job.
    • Dispatcher: Určuje vlákno nebo skupinu vláken, kde se korutina provádí.
  • Dispatchers: Vestavěné objekty pro správu vláken:
    • Dispatchers.Default: Obecná skupina vláken na pozadí.
    • Dispatchers.IO: Optimalizováno pro vstup/výstup (diskové, síťové operace).
    • Dispatchers.Main: Hlavní vlákno UI (pro Android, JavaFX atd.).
    • Dispatchers.Unconfined: Spouští korutinu v aktuálním vlákně, ale po pozastavení může pokračovat v libovolném vlákně.
    GlobalScope.launch(Dispatchers.IO) {
        // Provádí se v vlákně vstupu/výstupu
    }
    
  • Strukturovaná konkurence: Princip, podle kterého mají korutiny rodiče (CoroutineScope) a jsou automaticky zrušeny při zrušení rodiče. Zabraňuje únikům zdrojů a usnadňuje správu životního cyklu.
    // CoroutineScope automaticky spravuje podřízené korutiny
    val scope = CoroutineScope(Dispatchers.Default)
    val job = scope.launch {
        // ...
    }
    // Při zrušení scope jsou zrušeny všechny podřízené korutiny
    scope.cancel()
    
  • Kanály: Kanály pro bezpečný přenos dat mezi korutinami. Mohou být:
    • Unbuffered: Přijímání se provádí až po odeslání.
    • Buffered: Umožňuje odeslat několik prvků před blokováním.
    • Conflated: Ukládá pouze poslední odeslaný prvek.
    val channel = Channel<Int>()
    
    scope.launch {
        for (x in 1..5) channel.send(x)
        channel.close()
    }
    
    scope.launch {
        for (y in channel) println(y)
    }
    
  • Flow: Proud dat, který může emitovat několik hodnot asynchronně. Podobá se RxJava Observable, ale je lehčí a integrovaný s korutinami.
    fun simpleFlow(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(100)
            emit(i) // Odeslání hodnoty
        }
    }
    
    runBlocking {
        simpleFlow().collect { value -> println(value) } // Příjem hodnot
    }
    

Tyto možnosti umožňují psaní asynchronního kódu v imperativním stylu, což je čitelnější a lépe udržovatelné ve srovnání s použitím callbacků nebo Future.