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

Какие данные можно передавать через изоляты?

2.7 Senior🔥 151 комментариев
#Dart#Архитектура Flutter#Асинхронность

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

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

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

Какие данные можно передавать через изоляты?

В Dart Isolates работают с принципом полной изоляции памяти. Данные передаются между isolates через message passing, но не все типы данных можно передавать. Dart поддерживает передачу только serializable типов данных.

Поддерживаемые типы данных

1. Примитивные типы

// Все эти типы можно передавать
int number = 42;
double decimal = 3.14;
String text = "Hello";
bool flag = true;
Null nullValue = null;

2. Коллекции (List, Map, Set)

final list = [1, 2, 3, "text"];
final map = {"name": "John", "age": 30};
final set = {1, 2, 3};

// Все элементы должны быть serializable
final nested = {
  "data": [1, 2, 3],
  "config": {"enabled": true}
};

3. Enum значения

enum Status { pending, success, error }

final status = Status.success;
// Можно передавать через isolate

4. Класс Capability (специальные объекты)

ReceivePort port = ReceivePort();
var capability = port.sendPort;  // Передавается

Пример передачи данных

void isolateFunction(List<dynamic> args) {
  int number = args[0];
  String text = args[1];
  Map<String, dynamic> config = args[2];
  
  print("Received: $number, $text, $config");
}

void main() async {
  // Передаём список с разными типами
  final data = [
    42,
    "Hello",
    {"enabled": true, "count": 10}
  ];
  
  await Isolate.spawn(isolateFunction, data);
}

НЕЛЬЗЯ передавать

1. Пользовательские объекты (без специальной обработки)

class User {
  String name;
  int age;
  User(this.name, this.age);
}

void isolateFunc(User user) {  // ✗ ОШИБКА!
  print(user.name);
}

void main() async {
  var user = User("John", 30);
  // Ошибка при попытке отправить
  await Isolate.spawn(isolateFunc, user);
}

2. Функции и замыкания

void main() async {
  var callback = () => print("Callback");
  
  // ✗ ОШИБКА - функции нельзя передавать
  // await Isolate.spawn(someFunc, callback);
}

3. Объекты с состоянием (File, Socket)

import "dart:io";

void main() async {
  File file = File("data.txt");
  
  // ✗ ОШИБКА - нельзя передавать File
  // await Isolate.spawn(processFile, file);
}

4. BuildContext и Flutter widgets

// ✗ ОШИБКА
void isolateFunc(BuildContext context) {
  // BuildContext привязан к основному isolate
}

Решение: JSON сериализация

Для пользовательских объектов используйте JSON:

class User {
  String name;
  int age;
  
  User(this.name, this.age);
  
  // Преобразование в Map
  Map<String, dynamic> toMap() {
    return {"name": name, "age": age};
  }
  
  // Восстановление из Map
  factory User.fromMap(Map<String, dynamic> map) {
    return User(map["name"], map["age"]);
  }
}

void isolateFunc(Map<String, dynamic> userData) {
  var user = User.fromMap(userData);
  print("User: ${user.name}");
}

void main() async {
  var user = User("John", 30);
  var data = user.toMap();  // Преобразуем в Map
  
  await Isolate.spawn(isolateFunc, data);
}

Двусторонняя коммуникация

future workerIsolate(SendPort mainSendPort) async {
  final receivePort = ReceivePort();
  mainSendPort.send(receivePort.sendPort);
  
  // Получаем Map, обрабатываем, отправляем результат
  await for (var message in receivePort) {
    if (message is Map<String, dynamic>) {
      var result = {"processed": true, "data": message["value"] * 2};
      mainSendPort.send(result);
    }
  }
}

void main() async {
  final receivePort = ReceivePort();
  await Isolate.spawn(workerIsolate, receivePort.sendPort);
  
  final isolateSendPort = await receivePort.first;
  
  // Отправляем данные
  isolateSendPort.send({"value": 5});
  
  // Получаем результат
  receivePort.listen((result) {
    print("Result: $result");  // {"processed": true, "data": 10}
  });
}

Класс TransferableTypedData

Для больших бинарных данных используйте TransferableTypedData:

import "dart:typed_data";
import "dart:isolate";

void processData(List<dynamic> args) async {
  TransferableTypedData transferable = args[0];
  var data = transferable.materialize();
  
  print("Received ${data.buffer.lengthInBytes} bytes");
}

void main() async {
  var buffer = Uint8List(1024);
  var transferable = TransferableTypedData.fromList([buffer]);
  
  await Isolate.spawn(processData, [transferable]);
}

Таблица передаваемых типов

Тип              Передаётся   Примечание
─────────────────────────────────────────
int              ✓
double           ✓
String           ✓
bool             ✓
Null             ✓
List             ✓            Элементы тоже должны быть serializable
Map              ✓            Ключи и значения должны быть serializable
Set              ✓
Enum             ✓
SendPort         ✓            Для обратной коммуникации
Capability       ✓
Custom класс     ✗            Нужна сериализация в Map/JSON
Function         ✗
File/Socket      ✗
BuildContext     ✗            Привязан к главному isolate
Stream           ✗

Best Practices

  1. Переходите на Map/JSON для пользовательских объектов
// ✓ Хорошо
isolateSendPort.send({"id": 1, "name": "John"});

// ✗ Плохо
isolateSendPort.send(User("John"));
  1. Используйте typed messages для ясности
const messageTypeData = "data";
const messageTypeResult = "result";

isolateSendPort.send({"type": messageTypeData, "value": 42});
  1. Обрабатывайте большие данные осторожно
  • Копирование может быть дорого
  • Используйте TransferableTypedData для бинарных данных

Передача данных через isolates — фундаментальная концепция, которая требует понимания ограничений serialization в Dart.