# Dart Isolates та Конкурентність у 2026: compute, Async та Питання на Співбесідах > Опануйте ізоляти Dart, функцію compute та async патерни для Flutter застосунків. Розглядаються моделі конкурентності, оптимізація продуктивності та типові питання на співбесідах з прикладами коду. - Published: 2026-07-13 - Updated: 2026-07-13 - Author: SharpSkill - Tags: dart, flutter, isolates, concurrency, async, performance - Reading time: 12 min --- Ізоляти Dart забезпечують справжнє паралельне виконання у Flutter застосунках, вирішуючи проблему однопотокового обмеження, що спричиняє підлагування UI під час інтенсивних обчислень. На відміну від потоків в інших мовах, ізоляти не ділять пам'ять і спілкуються виключно через передачу повідомлень, що робить конкурентний код безпечнішим і простішим для розуміння. > **Ключова Інформація на 2026** > > Dart 3.7 представив легкі ізоляти зі зменшенням використання пам'яті на 50%. API `Isolate.run()` тепер обробляє більшість випадків використання, які раніше вимагали ручного створення ізолятів, тоді як `compute()` залишається переважним вибором для Flutter-специфічних навантажень. ## Розуміння Моделі Конкурентності Dart Dart виконує код в однопотоковому циклі подій всередині кожного ізоляту. Це означає, що async/await не забезпечує паралелізму — воно лише дозволяє неблокуючі I/O операції. Коли CPU-інтенсивна задача виконується на головному ізоляті, UI замерзає, оскільки цикл подій не може обробляти callback'и кадрів. Рішення полягає у винесенні важкої роботи до окремих ізолятів. Кожен ізолят має власну купу пам'яті та цикл подій, що працюють на окремому потоці, керованому Dart VM. Комунікація відбувається через `SendPort` та `ReceivePort`, які серіалізують повідомлення між ізолятами. ```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 } ``` Функція `Isolate.run()`, представлена в Dart 2.19, спрощує типовий патерн запуску одиничного обчислення у фоновому ізоляті. Вона автоматично обробляє створення портів, серіалізацію повідомлень та знищення ізоляту. ## Використання compute() у Flutter Застосунках Flutter надає функцію `compute()`, спеціально розроблену для винесення роботи з UI ізоляту. На відміну від сирих API ізолятів, `compute()` інтегрується з фреймворком Flutter та обробляє шаблонний код управління ізолятами. ```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); } } ``` Функція, передана до `compute()`, має бути функцією верхнього рівня або статичним методом. Методи екземплярів та замикання захоплюють стан, який не може бути серіалізований через межі ізолятів. > **Поширена Помилка** > > Передача несеріалізовуваних об'єктів до ізолятів спричиняє помилки виконання. Класи мають бути простими об'єктами даних — без `BuildContext`, без посилань на `Stream`, без синглтонів. Витягуйте лише примітивні дані, необхідні для обчислення. ## Двонаправлена Комунікація з Портами Складні сценарії вимагають постійної комунікації між ізолятами, а не одиничного циклу запит-відповідь. Довготривалі фонові задачі, потокова обробка даних та пули воркерів — усі потребують двонаправленої передачі повідомлень. ```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}; } ``` Цей патерн встановлює постійний ізолят воркера, який приймає множинні задачі з часом. Головний ізолят відправляє задачі через `SendPort`, а воркер відповідає через власний порт. Стан всередині ізоляту воркера зберігається між задачами, уможливлюючи кешування та інкрементальну обробку. ## Async/Await проти Ізолятів: Вибір Правильного Інструменту Поширеним [питанням на співбесіді для Flutter розробників](/technologies/flutter/interview-questions/state-management-basics) є коли використовувати async/await, а коли ізоляти. Це розрізнення важливе для продуктивності застосунку. | Сценарій | Використовуйте async/await | Використовуйте ізоляти | |----------|-----------------|-------------| | Мережеві запити | Так | Ні | | Файловий I/O | Так | Ні | | Парсинг JSON (малий) | Так | Ні | | Парсинг JSON (>1MB) | Ні | Так | | Обробка зображень | Ні | Так | | Криптографічні операції | Ні | Так | | Запити до бази даних | Так | Іноді | | Складні обчислення | Ні | Так | Async/await ефективно обробляє I/O-bound операції, оскільки Dart VM делегує очікування операційній системі. Цикл подій залишається вільним для обробки UI подій. Ізоляти вирішують CPU-bound проблеми, де саме обчислення споживає час незалежно від 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; } ``` ## Обробка Помилок Через Межі Ізолятів Помилки, кинуті в ізолятах, автоматично не поширюються до викликаючого ізоляту. Без належної обробки винятки зникають тихо, спричиняючи важко відстежувані проблеми у продакшн застосунках. ```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'); } ``` Патерн обгортки перехоплює винятки всередині ізоляту та повертає їх як дані, забезпечуючи видимість помилок у викликаючому коді. Цей підхід відображає [патерн Result, використовуваний у Rust](https://doc.rust-lang.org/std/result/) та узгоджується з практиками функціональної обробки помилок. ## Оптимізація Продуктивності з Пулами Ізолятів Створення ізолятів має накладні витрати — виділення пам'яті, JIT компіляція коду в новому ізоляті та серіалізація повідомлень. Для застосунків, що обробляють багато незалежних задач, повторне використання ізолятів через пул покращує пропускну здатність. ```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()); }); } ``` Пул підтримує фіксовану кількість прогрітих ізолятів, готових приймати роботу. Задачі стають у чергу, коли всі ізоляти зайняті, а завершені ізоляти негайно повертаються до доступного пулу. ## Типові Питання на Співбесідах про Конкурентність Dart Технічні співбесіди часто перевіряють розуміння моделі конкурентності Dart. Підготовка до цих питань демонструє глибину знань, що виходить за межі базового знання Flutter віджетів. [Модуль питань на співбесіді Flutter](/technologies/flutter) охоплює додаткові теми віджетів та управління станом. **П: Що станеться, якщо викликати setState() з ізоляту?** Виклик `setState()` з фонового ізоляту не вдасться, оскільки `BuildContext` та стан віджета існують лише в пам'яті головного ізоляту. Ізолят не може безпосередньо отримати доступ до об'єктів головного ізоляту. Натомість відправте обчислений результат назад до головного ізоляту і викличте `setState()` там: ```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; } ``` **П: Чи можуть ізоляти ділити об'єкти?** Ізоляти не можуть ділити змінювані об'єкти. Кожен ізолят має власну купу, і об'єкти, передані між ізолятами, серіалізуються та копіюються. Незмінні об'єкти та примітиви можуть передаватися ефективно, оскільки Dart оптимізує їх передачу. Змінюваний стан вимагає явної синхронізації через передачу повідомлень. **П: Як async/await працює з ізолятами?** Async/await всередині ізоляту працює ідентично до головного ізоляту — кожен ізолят має власний цикл подій. Очікування Future в ізоляті не блокує цикл подій головного ізоляту. Сама функція `Isolate.run()` повертає Future, що завершується коли ізолят закінчує роботу, безшовно інтегруючись з async кодом у головному ізоляті. ## Налагодження Коду на Основі Ізолятів Налагодження багатоізолятних застосунків вимагає розуміння того, що точки зупинки та логування поводяться по-різному через межі ізолятів. ```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; } ``` Вид продуктивності [Flutter DevTools](https://docs.flutter.dev/tools/devtools/overview) показує події таймлайну з усіх ізолятів, уможливлюючи візуалізацію паралельного виконання та ідентифікацію вузьких місць. > **Підказка DevTools** > > CPU Profiler у DevTools допомагає визначити, які ізоляти споживають найбільше часу обробки. Flame chart розділяє виконання за ізолятами, показуючи чи робота правильно розподілена. ## Висновок - Ізоляти забезпечують справжній паралелізм у Dart, працюючи на окремих потоках з ізольованими купами пам'яті - Використовуйте `Isolate.run()` для простих одноразових обчислень, `compute()` для Flutter-специфічних навантажень - Async/await обробляє I/O-bound роботу; ізоляти вирішують CPU-bound проблеми, що блокують цикл подій - Функції, передані до ізолятів, мають бути верхнього рівня або статичні — замикання та методи екземплярів не проходять серіалізацію - Реалізуйте обробку помилок всередині ізолятів і повертайте помилки як дані, щоб забезпечити належне виявлення винятків - Пули ізолятів зменшують накладні витрати створення для застосунків, що обробляють багато незалежних задач - [Модуль управління станом Flutter](/technologies/flutter/interview-questions/state-management-basics) доповнює знання конкурентності для підготовки до співбесід --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/uk/blog/flutter/dart-isolates-concurrency-2026-compute-async-interview