Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Isolates в Dart и Flutter
Isolate — это концепция из Dart для параллельного выполнения кода. В отличие от других языков, где используются потоки, Dart использует изоляты для настоящего параллелизма благодаря отсутствию shared-state concurrency.
Что такое Isolate
Isolate (изолят) — это независимый работник, который выполняет код параллельно с основным потоком. Каждый изолят имеет:
- Собственный event loop — обрабатывает асинхронные события
- Собственную память — не делится с другими изолятами
- Собственный Dart runtime — полная независимость
Основной thread (UI) │ Isolate #1 │ Isolate #2
─────────────────────────┼──────────────────────┼──────────────
build() │ │
setState() │ Heavy computation │ Heavy computation
renderFrame() │ (не блокирует UI) │ (не блокирует UI)
Почему нужны Isolates
Проблема: Dart is single-threaded
В отличие от многих языков, Dart выполняет весь код в одном потоке. Если одна операция занимает долго, весь UI замораживается:
// ❌ Плохо: блокирует UI
Future<void> fetchAndProcess() async {
final data = await api.fetchHeavyData(); // OK, async
final processed = processData(data); // ❌ БЛОКИРУЕТ! Если 5 сек
setState(() => result = processed);
}
// processData() выполняется синхронно и напрямую блокирует UI
List<int> processData(List<int> data) {
var result = [];
for (int i = 0; i < 10000000; i++) {
result.add(expensiveCalculation(data[i % data.length]));
}
return result; // 5 секунд! UI зависает!
}
Решение: Isolates
// ✅ Хорошо: используем изолят
Future<void> fetchAndProcess() async {
final data = await api.fetchHeavyData();
// Выполняй heavy работу в отдельном изоляте
final processed = await Isolate.run(() => processData(data));
setState(() => result = processed);
}
// processData выполняется в отдельном потоке, UI остается responsive
List<int> processData(List<int> data) {
var result = [];
for (int i = 0; i < 10000000; i++) {
result.add(expensiveCalculation(data[i % data.length]));
}
return result; // 5 секунд, но UI не зависает!
}
Практические примеры
Пример 1: Обработка больших объемов данных
import 'dart:isolate';
Future<List<String>> processLargeFile(File file) async {
// Читаем файл в основном потоке (быстро)
final content = await file.readAsString();
// Обрабатываем в отдельном изоляте (тяжело)
return await Isolate.run(() {
return content
.split('\n')
.map((line) => line.toUpperCase())
.where((line) => line.isNotEmpty)
.toList();
});
}
// Использование
var lines = await processLargeFile(myFile);
setState(() => displayLines = lines);
Пример 2: JSON парсинг
Future<List<User>> parseJsonUsers(String jsonString) {
// JSON парсинг может быть медленным на больших объемах
return Isolate.run(() {
final jsonData = jsonDecode(jsonString) as List;
return jsonData
.map((item) => User.fromJson(item))
.toList();
});
}
// Использование
Final users = await parseJsonUsers(jsonResponse);
Пример 3: Криптографические операции
Future<String> encryptData(String plainText, String key) {
return Isolate.run(() {
// Шифрование может быть очень медленным
final cipher = Cipher.aes(
plainText,
key,
encryptionMode: EncryptionMode.cbc,
);
return cipher.toBase64();
});
}
Пример 4: Долгоживущий isolate (передача сообщений)
class ImageProcessor {
late Isolate _isolate;
late SendPort _sendPort;
Future<void> initialize() async {
final receivePort = ReceivePort();
_isolate = await Isolate.spawn(
_imageProcessingEntryPoint,
receivePort.sendPort,
);
_sendPort = await receivePort.first;
}
static void _imageProcessingEntryPoint(SendPort mainSendPort) {
final port = ReceivePort();
mainSendPort.send(port.sendPort);
port.listen((message) {
if (message is String) {
final result = heavyImageProcessing(message);
message.reply(result);
}
});
}
Future<String> process(String imagePath) async {
final response = ReceivePort();
_sendPort.send([response.sendPort, imagePath]);
return await response.first;
}
void dispose() {
_isolate.kill();
}
}
Quando использовать Isolates
✅ Используй Isolates для:
- JSON парсинг больших объемов
- Обработка изображений (ресайз, фильтры, кроп)
- Криптография (шифрование, хеширование)
- Вычисления (ML модели, большие матрицы)
- Работа с файлами (сжатие, конвертация)
- Database операции (сложные запросы)
// Пример: обработка множество изображений
Future<List<Image>> processImages(List<String> imagePaths) {
return Isolate.run(() {
return imagePaths
.map((path) => _processImage(path))
.toList();
});
}
❌ НЕ используй Isolates для:
- Быстрые операции (<50ms) — overhead изолята замедлит
- UI обновления — UI работает только в main isolate
- Сетевые запросы — используй async/await
- Простые вычисления — overhead не оправдает
// ❌ Неправильно: Isolate для простого вычисления
await Isolate.run(() => 2 + 2); // Overhead > результат
// ✅ Правильно: async/await для сети
final data = await http.get(url);
Производительность
Время создания Isolate:
Основной isolate (main): 0 ms (already running)
Создание нового isolate: 50-200 ms (зависит от устройства)
Отправка сообщения: <1 ms
Получение ответа: <1 ms
Практический чек-лист:
Операция займет: 50ms → 500ms → 5000ms
───────────────── ───────────────────────
Лучше async/await Рассмотрим isolate Обязательно isolate
Лучшие практики
-
Используй
Isolate.run()для простых случаевfinal result = await Isolate.run(() => heavyWork()); -
Используй долгоживущие isolates для повторяющихся операций
// Если нужно обрабатывать 1000+ изображений final processor = ImageProcessor(); await processor.initialize(); for (var path in paths) { final result = await processor.process(path); } -
Всегда обрабатывай ошибки
try { final result = await Isolate.run(() => riskyWork()); } catch (e) { print('Isolate error: $e'); } -
Не передавай большие объекты
// ❌ Плохо: копирование больших данных await Isolate.run(() => process(hugeList)); // Медленно // ✅ Хорошо: передай только необходимое await Isolate.run(() => process(hugeList.sublist(0, 100)));
Альтернативы в Flutter
-
compute() функция — обёртка над
Isolate.run()для FlutterDelegateimport 'package:flutter/foundation.dart'; final result = await compute(heavyWork, param); -
Background Isolate с методом каналов для интеграции с платформой (iOS/Android)
Isolates — это мощный инструмент для обработки heavy work без блокирования UI. Но помни: overhead создания изолята должен быть меньше выигрыша от параллельного выполнения.