← Назад к вопросам

Как создать изолят?

2.0 Middle🔥 121 комментариев
#Асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Изоляты (Isolates) в Dart/Flutter

Изолят — это независимый поток выполнения в Dart, который имеет собственную кучу памяти и не разделяет переменные с другими изолятами. Это решение для параллелизма в Dart, позволяющее выполнять тяжелые операции без блокировки главного потока.

Зачем нужны изоляты

// ПРОБЛЕМА: блокирует главный поток UI
void heavyComputation() {
  // Это заморозит UI на несколько секунд
  int sum = 0;
  for (int i = 0; i < 1000000000; i++) {
    sum += i;
  }
  print("Sum: $sum");
}

// РЕШЕНИЕ: использовать изолят
Future<int> heavyComputationInIsolate() async {
  return await compute(heavyComputation, null);
}

void heavyComputation(dynamic _) {
  int sum = 0;
  for (int i = 0; i < 1000000000; i++) {
    sum += i;
  }
  print("Sum: $sum");
}

Простой способ: compute()

compute() — это встроенная функция Flutter для выполнения функции в новом изоляте.

import 'package:flutter/foundation.dart';

// Функция, которая будет запущена в изоляте
int calculateFibonacci(int n) {
  if (n <= 1) return n;
  return calculateFibonacci(n - 1) + calculateFibonacci(n - 2);
}

// Функция для обработки JSON (тяжелая операция)
List<User> parseJsonList(String jsonString) {
  final List<dynamic> json = jsonDecode(jsonString);
  return json.map((item) => User.fromJson(item)).toList();
}

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late Future<int> _fib;
  late Future<List<User>> _users;
  
  @override
  void initState() {
    super.initState();
    
    // Запуск вычисления в изоляте
    _fib = compute(calculateFibonacci, 40);
    
    // Парсинг больших данных в изоляте
    _users = compute(parseJsonList, largeJsonString);
  }
  
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<int>(
      future: _fib,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text("Error: ${snapshot.error}");
        } else {
          return Text("Fibonacci(40) = ${snapshot.data}");
        }
      },
    );
  }
}

Полный контроль: Isolate.spawn()

import 'dart:isolate';

// Функция, которая будет запущена в новом изоляте
void isolateEntryPoint(SendPort sendPort) {
  // Получаем ReceivePort для общения
  final receivePort = ReceivePort();
  sendPort.send(receivePort.sendPort);
  
  // Слушаем сообщения
  receivePort.listen((message) {
    if (message is String && message == "fibonacci") {
      int result = calculateFibonacci(40);
      sendPort.send(result);
    } else if (message == "stop") {
      receivePort.close();
    }
  });
}

class IsolateManager {
  late Isolate _isolate;
  late ReceivePort _receivePort;
  late SendPort _sendPort;
  
  Future<void> initialize() async {
    // Создаём ReceivePort в главном изоляте
    _receivePort = ReceivePort();
    
    // Создаём новый изолят
    _isolate = await Isolate.spawn(
      isolateEntryPoint,
      _receivePort.sendPort,
    );
    
    // Получаем SendPort из изолята
    _sendPort = await _receivePort.first;
  }
  
  Future<int> calculateFibonacci() async {
    // Создаём новый ReceivePort для получения результата
    final resultPort = ReceivePort();
    
    // Отправляем команду
    _sendPort.send("fibonacci");
    
    // Ждём результат
    final result = await resultPort.first;
    resultPort.close();
    
    return result;
  }
  
  void dispose() {
    _sendPort.send("stop");
    _isolate.kill();
    _receivePort.close();
  }
}

Практический пример: обработка больших файлов

import 'dart:isolate';

// Функция в изоляте
Future<List<String>> processLargeFile(String filePath) async {
  final file = File(filePath);
  final lines = await file.readAsLines();
  
  // Какая-то тяжелая обработка
  return lines
      .where((line) => line.isNotEmpty)
      .map((line) => line.toUpperCase())
      .toList();
}

// Использование с compute
class FileProcessor {
  Future<List<String>> processFile(String path) async {
    return await compute(processLargeFile, path);
  }
}

Обмен данными между изолятами

import 'dart:isolate';

void workerIsolate(SendPort mainSendPort) {
  final receivePort = ReceivePort();
  mainSendPort.send(receivePort.sendPort);
  
  receivePort.listen((dynamic message) {
    if (message is Map) {
      final numbers = message["numbers"] as List<int>;
      final sum = numbers.reduce((a, b) => a + b);
      mainSendPort.send({"result": sum});
    }
  });
}

class IsolateWorker {
  late SendPort _workerSendPort;
  late ReceivePort _mainReceivePort;
  late Isolate _isolate;
  
  Future<void> init() async {
    _mainReceivePort = ReceivePort();
    _isolate = await Isolate.spawn(workerIsolate, _mainReceivePort.sendPort);
    _workerSendPort = await _mainReceivePort.first as SendPort;
  }
  
  Future<int> sumNumbers(List<int> numbers) async {
    final responsePort = ReceivePort();
    _workerSendPort.send({
      "numbers": numbers,
      "responsePort": responsePort.sendPort,
    });
    
    final response = await responsePort.first as Map;
    return response["result"] as int;
  }
  
  void dispose() {
    _isolate.kill();
    _mainReceivePort.close();
  }
}

void main() async {
  final worker = IsolateWorker();
  await worker.init();
  
  final result = await worker.sumNumbers([1, 2, 3, 4, 5]);
  print("Sum: $result"); // Sum: 15
  
  worker.dispose();
}

Изоляты в фоновых задачах

class BackgroundService {
  static Future<void> backgroundTask(dynamic message) async {
    // Тяжелая фоновая работа
    print("Running background task...");
    await Future.delayed(Duration(seconds: 5));
    print("Background task completed");
  }
}

// Использование в Flutter
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  void _startBackgroundWork() async {
    // Запускаем тяжелую работу в фоновом изоляте
    await compute(BackgroundService.backgroundTask, null);
    
    print("Background work done");
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: _startBackgroundWork,
          child: Text("Start Background Work"),
        ),
      ),
    );
  }
}

Лучшие практики

Используй compute() для простых операций:

final result = await compute(myFunction, input);

Используй Isolate.spawn() для сложных операций с двусторонней коммуникацией:

final isolate = await Isolate.spawn(entryPoint, sendPort);

Закрывай ReceivePort когда больше не нужен:

receivePort.close();

Убивай изолят когда закончил:

isolate.kill();

Избегай передачи больших объектов между изолятами (копируются, медленно)

Не забывай про обработку ошибок в изолятах

Различие между compute() и Isolate.spawn()

Аспектcompute()Isolate.spawn()
СложностьПростой APIБольше контроля
Двусторонняя связьНетДа
Время жизниАвтоматическое управлениеРучное управление
ИспользованиеОдноразовые операцииДолгоживущие рабочие
Для начинающихРекомендуетсяДля опытных

Заключение

Изоляты — это мощный инструмент для создания отзывчивых Flutter приложений. Для большинства случаев используй compute(), но когда нужна сложная многоправная коммуникация, используй Isolate.spawn(). Правильное использование изолятов делает приложение быстрым и отзывчивым.