# Dart Isolates i Współbieżność w 2026: compute, Async oraz Pytania Rekrutacyjne > Kompleksowy przewodnik po izolatkach Dart, funkcji compute i wzorcach async dla aplikacji Flutter. Omówienie modeli współbieżności, optymalizacji wydajności oraz typowych pytań rekrutacyjnych z przykładami kodu. - Published: 2026-07-13 - Updated: 2026-07-13 - Author: SharpSkill - Tags: dart, flutter, isolates, concurrency, async, performance - Reading time: 12 min --- Izolatki Dart zapewniają prawdziwą równoległą egzekucję w aplikacjach Flutter, rozwiązując problem jednowątkowych ograniczeń powodujących zacinanie się interfejsu użytkownika podczas intensywnych obliczeń. W przeciwieństwie do wątków w innych językach, izolatki nie współdzielą pamięci i komunikują się wyłącznie poprzez przekazywanie wiadomości, co sprawia, że kod współbieżny jest bezpieczniejszy i łatwiejszy do zrozumienia. > **Kluczowe Informacje na 2026** > > Dart 3.7 wprowadził lekkie izolatki z 50% zmniejszonym zużyciem pamięci. API `Isolate.run()` obsługuje teraz większość przypadków użycia, które wcześniej wymagały ręcznego tworzenia izolatek, podczas gdy `compute()` pozostaje preferowaną opcją dla zadań specyficznych dla Flutter. ## Zrozumienie Modelu Współbieżności Dart Dart wykonuje kod w jednowątkowej pętli zdarzeń wewnątrz każdej izolatki. Oznacza to, że async/await nie zapewnia równoległości — pozwala jedynie na nieblokujące operacje I/O. Gdy zadanie wymagające intensywnych obliczeń CPU uruchamia się na głównej izolatce, interfejs użytkownika zamraża się, ponieważ pętla zdarzeń nie może przetwarzać wywołań zwrotnych ramek. Rozwiązaniem jest przeniesienie ciężkiej pracy do oddzielnych izolatek. Każda izolatka ma własną stertę pamięci i pętlę zdarzeń, działającą na osobnym wątku zarządzanym przez maszynę wirtualną Dart. Komunikacja odbywa się poprzez `SendPort` i `ReceivePort`, które serializują wiadomości między izolatkami. ```dart // main.dart import 'dart:isolate'; // Heavy computation that would block the UI if run on main isolate int computeFibonacci(int n) { if (n <= 1) return n; return computeFibonacci(n - 1) + computeFibonacci(n - 2); } Future main() async { // Isolate.run() handles spawning, message passing, and cleanup automatically final result = await Isolate.run(() => computeFibonacci(40)); print('Fibonacci(40) = $result'); // Computed without blocking main thread } ``` Funkcja `Isolate.run()` wprowadzona w Dart 2.19 upraszcza typowy wzorzec uruchamiania pojedynczego obliczenia w izolatce działającej w tle. Automatycznie obsługuje tworzenie portów, serializację wiadomości i usuwanie izolatki. ## Używanie compute() w Aplikacjach Flutter Flutter dostarcza funkcję `compute()` zaprojektowaną specjalnie do przenoszenia pracy z izolatki UI. W przeciwieństwie do surowych API izolatek, `compute()` integruje się z frameworkiem Flutter i obsługuje standardowy kod zarządzania izolatkami. ```dart // image_processor.dart import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:image/image.dart' as img; // Top-level function required for compute() - cannot be a closure or method Uint8List _applyGrayscaleFilter(Uint8List imageBytes) { final image = img.decodeImage(imageBytes)!; final grayscale = img.grayscale(image); return Uint8List.fromList(img.encodePng(grayscale)); } class ImageProcessor { Future processImage(Uint8List rawImage) async { // compute() spawns isolate, runs function, returns result, disposes isolate return await compute(_applyGrayscaleFilter, rawImage); } } ``` Funkcja przekazywana do `compute()` musi być funkcją najwyższego poziomu lub metodą statyczną. Metody instancji i domknięcia przechwytują stan, który nie może być serializowany między granicami izolatek. > **Częsty Błąd** > > Przekazywanie obiektów niemożliwych do serializacji do izolatek powoduje błędy w czasie wykonywania. Klasy muszą być prostymi obiektami danych — bez `BuildContext`, bez referencji do `Stream`, bez singletonów. Należy wyodrębnić tylko prymitywne dane potrzebne do obliczeń. ## Dwukierunkowa Komunikacja z Portami Złożone scenariusze wymagają ciągłej komunikacji między izolatkami zamiast pojedynczego cyklu żądanie-odpowiedź. Długotrwałe zadania w tle, przetwarzanie strumieniowe danych i pule workerów wymagają dwukierunkowego przekazywania wiadomości. ```dart // background_worker.dart import 'dart:isolate'; import 'dart:async'; class BackgroundWorker { late Isolate _isolate; late SendPort _sendPort; final _responseController = StreamController.broadcast(); Stream get responses => _responseController.stream; Future start() async { final receivePort = ReceivePort(); // Spawn isolate with initial SendPort for bidirectional setup _isolate = await Isolate.spawn(_workerEntryPoint, receivePort.sendPort); // First message from worker contains its SendPort final completer = Completer(); receivePort.listen((message) { if (message is SendPort) { completer.complete(message); } else { _responseController.add(message); // Forward results to stream } }); _sendPort = await completer.future; } void sendTask(Map task) { _sendPort.send(task); } void dispose() { _isolate.kill(priority: Isolate.immediate); _responseController.close(); } } // Entry point runs in the background isolate void _workerEntryPoint(SendPort mainSendPort) { final workerReceivePort = ReceivePort(); mainSendPort.send(workerReceivePort.sendPort); // Send port back to main workerReceivePort.listen((message) { final task = message as Map; final result = _processTask(task); // Heavy computation here mainSendPort.send(result); }); } dynamic _processTask(Map task) { // Simulate CPU-intensive work return {'taskId': task['id'], 'processed': true}; } ``` Ten wzorzec ustanawia trwałą izolatkę workera, która akceptuje wiele zadań w czasie. Główna izolatka wysyła zadania przez `SendPort`, a worker odpowiada przez własny port. Stan wewnątrz izolatki workera utrzymuje się między zadaniami, umożliwiając buforowanie i przyrostowe przetwarzanie. ## Async/Await vs Izolatki: Wybór Właściwego Narzędzia Częstym [pytaniem rekrutacyjnym dla programistów Flutter](/technologies/flutter/interview-questions/state-management-basics) jest kiedy używać async/await, a kiedy izolatek. To rozróżnienie ma znaczenie dla wydajności aplikacji. | Scenariusz | Użyj async/await | Użyj izolatek | |----------|-----------------|-------------| | Żądania sieciowe | Tak | Nie | | I/O plików | Tak | Nie | | Parsowanie JSON (małe) | Tak | Nie | | Parsowanie JSON (>1MB) | Nie | Tak | | Przetwarzanie obrazów | Nie | Tak | | Operacje kryptograficzne | Nie | Tak | | Zapytania bazodanowe | Tak | Czasami | | Złożone obliczenia | Nie | Tak | Async/await efektywnie obsługuje operacje związane z I/O, ponieważ maszyna wirtualna Dart deleguje oczekiwanie do systemu operacyjnego. Pętla zdarzeń pozostaje wolna do przetwarzania zdarzeń UI. Izolatki rozwiązują problemy związane z CPU, gdzie samo obliczenie zajmuje czas niezależnie od I/O. ```dart // json_service.dart import 'dart:convert'; import 'package:flutter/foundation.dart'; class JsonService { // Small payloads: async is sufficient, isolate overhead not justified Future> parseSmallJson(String json) async { return jsonDecode(json) as Map; } // Large payloads: isolate prevents UI jank during parsing Future> parseLargeJson(String json) async { return await compute(_parseJsonList, json); } } List _parseJsonList(String json) { return jsonDecode(json) as List; } ``` ## Obsługa Błędów Między Granicami Izolatek Błędy rzucane w izolatkach nie propagują się automatycznie do izolatki wywołującej. Bez odpowiedniej obsługi, wyjątki znikają po cichu, powodując trudne do debugowania problemy w aplikacjach produkcyjnych. ```dart // safe_isolate.dart import 'dart:isolate'; class IsolateResult { final T? value; final Object? error; final StackTrace? stackTrace; IsolateResult.success(this.value) : error = null, stackTrace = null; IsolateResult.failure(this.error, this.stackTrace) : value = null; bool get isSuccess => error == null; } Future> runSafeIsolate(T Function() computation) async { try { final result = await Isolate.run(() { try { return IsolateResult.success(computation()); } catch (e, stack) { return IsolateResult.failure(e, stack); } }); return result; } catch (e, stack) { // Handle isolate spawn failures return IsolateResult.failure(e, stack); } } // Usage Future processData() async { final result = await runSafeIsolate(() => riskyComputation()); if (result.isSuccess) { print('Result: ${result.value}'); } else { print('Error: ${result.error}'); print('Stack: ${result.stackTrace}'); } } int riskyComputation() { throw Exception('Something went wrong'); } ``` Wzorzec opakowania przechwytuje wyjątki wewnątrz izolatki i zwraca je jako dane, zapewniając że błędy ujawniają się w kodzie wywołującym. To podejście odzwierciedla [wzorzec Result używany w Rust](https://doc.rust-lang.org/std/result/) i jest zgodne z praktykami funkcyjnej obsługi błędów. ## Optymalizacja Wydajności z Pulami Izolatek Tworzenie izolatek wiąże się z narzutem — alokacją pamięci, kompilacją JIT kodu w nowej izolatce i serializacją wiadomości. Dla aplikacji przetwarzających wiele niezależnych zadań, ponowne wykorzystanie izolatek poprzez pulę poprawia przepustowość. ```dart // isolate_pool.dart import 'dart:async'; import 'dart:collection'; import 'dart:isolate'; class IsolatePool { final int size; final Queue<_PooledIsolate> _available = Queue(); final List<_PooledIsolate> _all = []; bool _initialized = false; IsolatePool({this.size = 4}); Future initialize() async { if (_initialized) return; for (int i = 0; i < size; i++) { final pooled = await _PooledIsolate.spawn(); _all.add(pooled); _available.add(pooled); } _initialized = true; } Future execute(R Function() task) async { if (!_initialized) await initialize(); // Wait for available isolate while (_available.isEmpty) { await Future.delayed(const Duration(milliseconds: 10)); } final isolate = _available.removeFirst(); try { return await isolate.run(task); } finally { _available.add(isolate); // Return to pool } } Future dispose() async { for (final isolate in _all) { isolate.dispose(); } _all.clear(); _available.clear(); } } class _PooledIsolate { final Isolate isolate; final SendPort sendPort; final ReceivePort receivePort; _PooledIsolate._(this.isolate, this.sendPort, this.receivePort); static Future<_PooledIsolate> spawn() async { final receivePort = ReceivePort(); final isolate = await Isolate.spawn(_poolWorker, receivePort.sendPort); final sendPort = await receivePort.first as SendPort; return _PooledIsolate._(isolate, sendPort, receivePort); } Future run(R Function() task) async { final responsePort = ReceivePort(); sendPort.send([task, responsePort.sendPort]); return await responsePort.first as R; } void dispose() { isolate.kill(); receivePort.close(); } } void _poolWorker(SendPort mainPort) { final workerPort = ReceivePort(); mainPort.send(workerPort.sendPort); workerPort.listen((message) { final task = message[0] as Function; final replyPort = message[1] as SendPort; replyPort.send(task()); }); } ``` Pula utrzymuje stałą liczbę rozgrzanych izolatek gotowych do przyjęcia pracy. Zadania kolejkują się, gdy wszystkie izolatki są zajęte, a ukończone izolatki natychmiast wracają do dostępnej puli. ## Typowe Pytania Rekrutacyjne o Współbieżność Dart Rozmowy techniczne często badają zrozumienie modelu współbieżności Dart. Przygotowanie do tych pytań demonstruje głębię wykraczającą poza podstawową wiedzę o widgetach Flutter. [Moduł pytań rekrutacyjnych Flutter](/technologies/flutter) obejmuje dodatkowe tematy dotyczące widgetów i zarządzania stanem. **P: Co się stanie, jeśli wywołasz setState() z izolatki?** Wywołanie `setState()` z izolatki działającej w tle nie powiedzie się, ponieważ `BuildContext` i stan widgetu istnieją tylko w pamięci głównej izolatki. Izolatka nie może bezpośrednio uzyskać dostępu do obiektów głównej izolatki. Zamiast tego należy wysłać obliczony wynik z powrotem do głównej izolatki i wywołać `setState()` tam: ```dart // counter_page.dart import 'dart:isolate'; import 'package:flutter/material.dart'; class CounterPage extends StatefulWidget { const CounterPage({super.key}); @override State createState() => _CounterPageState(); } class _CounterPageState extends State { int _result = 0; bool _computing = false; Future _computeInBackground() async { setState(() => _computing = true); // Computation runs in isolate final result = await Isolate.run(() => _heavyCalculation(1000000)); // setState called on main isolate after receiving result setState(() { _result = result; _computing = false; }); } @override Widget build(BuildContext context) { return Column( children: [ Text('Result: $_result'), ElevatedButton( onPressed: _computing ? null : _computeInBackground, child: _computing ? const CircularProgressIndicator() : const Text('Compute'), ), ], ); } } int _heavyCalculation(int iterations) { int sum = 0; for (int i = 0; i < iterations; i++) { sum += i; } return sum; } ``` **P: Czy izolatki mogą współdzielić obiekty?** Izolatki nie mogą współdzielić zmiennych obiektów. Każda izolatka ma własną stertę, a obiekty przekazywane między izolatkami są serializowane i kopiowane. Niezmienne obiekty i prymitywy mogą być przekazywane efektywnie, ponieważ Dart optymalizuje ich transfer. Zmienny stan wymaga jawnej synchronizacji poprzez przekazywanie wiadomości. **P: Jak async/await działa z izolatkami?** Async/await wewnątrz izolatki działa identycznie jak w głównej izolatce — każda izolatka ma własną pętlę zdarzeń. Oczekiwanie na Future w izolatce nie blokuje pętli zdarzeń głównej izolatki. Sama funkcja `Isolate.run()` zwraca Future, który kończy się po zakończeniu izolatki, integrując się płynnie z kodem asynchronicznym w głównej izolatce. ## Debugowanie Kodu Opartego na Izolatkach Debugowanie aplikacji wieloizolatkowych wymaga zrozumienia, że punkty przerwania i logowanie zachowują się inaczej między granicami izolatek. ```dart // debug_utils.dart import 'dart:developer' as developer; import 'dart:isolate'; void debugPrint(String message) { // developer.log works across isolates and appears in DevTools developer.log( message, name: 'IsolateDebug', time: DateTime.now(), ); } Future debuggableComputation() async { await Isolate.run(() { debugPrint('Starting computation in isolate'); // Timeline events visible in DevTools performance tab developer.Timeline.startSync('HeavyWork'); final result = performHeavyWork(); developer.Timeline.finishSync(); debugPrint('Computation complete: $result'); return result; }); } int performHeavyWork() { int sum = 0; for (int i = 0; i < 10000000; i++) { sum += i; } return sum; } ``` Widok wydajności [Flutter DevTools](https://docs.flutter.dev/tools/devtools/overview) pokazuje zdarzenia osi czasu ze wszystkich izolatek, umożliwiając wizualizację równoległego wykonania i identyfikację wąskich gardeł. > **Wskazówka DevTools** > > Profiler CPU w DevTools pomaga zidentyfikować, które izolatki zużywają najwięcej czasu przetwarzania. Wykres płomieniowy rozdziela wykonanie według izolatki, ujawniając czy praca jest właściwie rozłożona. ## Podsumowanie - Izolatki zapewniają prawdziwą równoległość w Dart, działając na oddzielnych wątkach z izolowanymi stertami pamięci - Używaj `Isolate.run()` dla prostych jednorazowych obliczeń, `compute()` dla zadań specyficznych dla Flutter - Async/await obsługuje pracę związaną z I/O; izolatki rozwiązują problemy związane z CPU, które blokują pętlę zdarzeń - Funkcje przekazywane do izolatek muszą być najwyższego poziomu lub statyczne — domknięcia i metody instancji nie przechodzą serializacji - Implementuj obsługę błędów wewnątrz izolatek i zwracaj błędy jako dane, aby zapewnić właściwe ujawnienie wyjątków - Pule izolatek zmniejszają narzut tworzenia dla aplikacji przetwarzających wiele niezależnych zadań - [Moduł zarządzania stanem Flutter](/technologies/flutter/interview-questions/state-management-basics) uzupełnia wiedzę o współbieżności w przygotowaniu do rozmów rekrutacyjnych --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/flutter/dart-isolates-concurrency-2026-compute-async-interview