Sobes.tech
Middle

Ako vytvoriť dva vlákna v Dart v kontexte Flutter?

sobes.tech AI

Odpoveď od AI

V Dart/Flutter sa se za kreiranje nezávislých tokov vykonávania používajú izoláty (Isolates). Predstavujú samostatné úlohy s vlastným vyhradeným priestorom pamäte, čo zabraňuje problémom s konkurenčným prístupom k údajom a blokovaniu hlavného vlákna (UI vlákna).

Existuje niekoľko spôsobov, ako vytvárať a komunikovať s izolátmi:

  1. Isolate.spawn(): Najnižšia úroveň vytvárania izolátu. Vyžaduje odovzdanie funkcie vyššej úrovne alebo statickej metódy triedy na vykonanie v novom izoláte a portu na výmenu správ.

    import 'dart:isolate';
    
    // Funkcia, ktorá sa vykonáva v izoláte
    void isolateEntry(SendPort sendPort) {
      // Vykonávame nejakú dlhú operáciu
      int result = 0;
      for (int i = 0; i < 1000000000; i++) {
        result += i;
      }
      // Odosielame výsledok späť hlavného izolátu
      sendPort.send(result);
    }
    
    void main() async {
      ReceivePort receivePort = ReceivePort();
      // Vytvorenie nového izolátu
      Isolate isolate = await Isolate.spawn(isolateEntry, receivePort.sendPort);
    
      // Počúvame správy od izolátu
      receivePort.listen((message) {
        print('Výsledok z izolátu: $message');
        // Ukončíme izolát po prijatí správy
        isolate.kill();
      });
    
      print('Hlavný tok pokračuje v práci...');
    }
    
  2. compute(): Zjednodušená funkcia z balíka flutter/foundation, ktorá používa Isolate.spawn() na pozadí. Ideálna pre jednoduché úlohy na pozadí, ktoré nevyžadujú zložitú komunikáciu s izolátom.

    import 'package:flutter/foundation.dart';
    
    // Funkcia, ktorá sa vykonáva pomocou compute
    int heavyComputation(int limit) {
      int result = 0;
      for (int i = 0; i < limit; i++) {
        result += i;
      }
      return result;
    }
    
    void main() async {
      print('Začíname ťažké výpočty na pozadí...');
      // Spúšťame funkciu v samostatnom izoláte
      int result = await compute(heavyComputation, 1000000000);
      print('Výsledok výpočtov: $result');
      print('Hlavný tok pokračuje po výpočtoch.');
    }
    
  3. Isolate.spawnUri(): Používa sa na spustenie kódu z samostatného súboru dart v novom izoláte.

Interakcia medzi izolátmi:

Izoláty si vymieňajú údaje iba prostredníctvom odosielania správ cez inštancie SendPort a ReceivePort. Ide o atomárne operácie, ktoré nevyžadujú zámky alebo iné mechanizmy na synchronizáciu.

  • SendPort: Používa sa na odosielanie správ z jedného izolátu do druhého.
  • ReceivePort: Používa sa na sledovanie prichádzajúcich správ.

Pri prenose objektov medzi izolátmi musia byť objekty "prenášateľné" (transferable), čo zahŕňa:

  • Jednoduché dátové typy (int, double, String, bool)
  • Zoznamy a mapy obsahujúce prenášateľné typy
  • Niektoré špecifické typy Flutteru, ktoré je možné serializovať

Objekty, ktoré nie sú prenášateľné, budú skopírované a ich následné zmeny v jednom izoláte sa neprejavia v inom.

Kľúčové body:

  • Izoláty nemôžu priamo pristupovať k pamäti iných.
  • Nemajú prístup k spoločnému stavu, vrátane premenných, tried a widgetov hlavného izolátu (UI vlákna).
  • Komunikácia medzi izolátmi prebieha asynchrónne.
  • V Flutteri je dôležité správne spravovať ich životný cyklus (napríklad použitím isolate.kill() ak je to potrebné).

Použitie izolátov umožňuje vykonávanie dlhých alebo zdrojovo náročných operácií na pozadí, čím sa zabraňuje zaseknutiu používateľského rozhrania a zabezpečuje plynulý chod aplikácie.