Sobes.tech
Middle

Aké možnosti ponúka Kotlin na prácu s asynchrónnymi operáciami?

sobes.tech AI

Odpoveď od AI

Kotlin poskytuje korutiny (coroutines) na zjednodušenie asynchrónnych operácií a ponúka ľahké prúdy, ktoré nezablokujú hlavný vlákno vykonávania.

Kľúčové možnosti:

  • Funkcie pozastavenia: Funkcie s kľúčovým slovom suspend, ktoré môžu byť pozastavené a pokračovať. Nezablokujú vlákno, v ktorom sa vykonávajú.
    suspend fun fetchData(): String {
        delay(1000) // Imituje dlhú operáciu
        return "Dáta získané"
    }
    
  • Stavitelia korutín: Funkcie používané na spustenie korutín:
    • launch: Spustí novú korutinu a vráti Job (neblokuje).
      GlobalScope.launch {
          println("Korutina spustená")
      }
      
    • async: Spustí novú korutinu a vráti Deferred<T> (blokuje pri volaní .await()).
      val deferred = GlobalScope.async {
          fetchData()
      }
      // ...
      val result = deferred.await() // Čaká na výsledok
      
    • runBlocking: Blokuje aktuálne vlákno do dokončenia korutiny (používa sa hlavne ako most medzi blokujúcim a neblokujúcim kódom, napríklad v testoch).
      runBlocking {
          val data = fetchData()
          println(data)
      }
      
  • CoroutineContext: Súbor prvkov, ktoré určujú správanie korutiny, vrátane Dispatcher a Job.
    • Dispatcher: Určuje vlákno alebo skupinu vlákien, kde sa korutina vykonáva.
  • Dispatchers: Vstavané objekty na správu vlákien:
    • Dispatchers.Default: Všeobecný bazén pozadijných vlákien.
    • Dispatchers.IO: Optimalizované pre vstup/výstup (diskové, sieťové operácie).
    • Dispatchers.Main: Hlavné vlákno UI (pre Android, JavaFX atď.).
    • Dispatchers.Unconfined: Spúšťa korutinu v aktuálnom vlákne, ale po pozastavení môže pokračovať v ľubovoľnom vlákne.
    GlobalScope.launch(Dispatchers.IO) {
        // Vykonáva sa v vstupe/výstupe vlákne
    }
    
  • Štruktúrovaná konkurencia: Princíp, podľa ktorého majú korutiny rodiča (CoroutineScope) a sú automaticky zrušené pri zrušení rodiča. Zabraňuje únikom zdrojov a uľahčuje správu životného cyklu.
    // CoroutineScope automaticky spravuje dcérske korutiny
    val scope = CoroutineScope(Dispatchers.Default)
    val job = scope.launch {
        // ...
    }
    // Pri zrušení scope sú zrušené všetky dcérske korutiny
    scope.cancel()
    
  • Kanály: Kanály na bezpečný prenos dát medzi korutinami. Môžu byť:
    • Unbuffered: Prijímanie sa vykonáva až po odoslaní.
    • Buffered: Umožňuje odoslať niekoľko prvkov pred blokovaním.
    • Conflated: Ukladá iba posledný odoslaný prvok.
    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: Tok dát, ktorý môže emitovať niekoľko hodnôt asynchrónne. Podobá sa RxJava Observable, ale je ľahší a integrovaný s korutinami.
    fun simpleFlow(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(100)
            emit(i) // Odoslanie hodnoty
        }
    }
    
    runBlocking {
        simpleFlow().collect { value -> println(value) } // Spotreba hodnôt
    }
    

Tieto možnosti umožňujú písanie asynchrónneho kódu v imperatívnom štýle, čím je čitateľnejší a ľahšie udržiavateľný v porovnaní s používaním callbackov alebo Future.