Ответ
В Dart/Flutter я работаю с многопоточностью через изоляты (isolates), так как Dart использует модель акторов с разделяемой-nothing архитектурой:
1. Базовые изоляты для CPU-intensive задач:
// Создание простого изолята
Future<void> runInIsolate() async {
final receivePort = ReceivePort();
await Isolate.spawn(
_heavyComputation,
receivePort.sendPort, // Передаем порт для коммуникации
);
// Получаем результат из изолята
final result = await receivePort.first;
print('Result from isolate: $result');
}
void _heavyComputation(SendPort sendPort) {
// Этот код выполняется в отдельном изоляте
final result = performExpensiveCalculation();
sendPort.send(result);
}
2. Упрощенный API через compute():
// Для одноразовых задач
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
void calculateFibonacci() async {
// compute автоматически создает изолят, выполняет функцию
// и возвращает результат
final result = await compute(fibonacci, 40);
print('Fibonacci(40) = $result');
}
3. Продвинутые сценарии с несколькими изолятами:
// Создание пула изолятов для параллельной обработки
class IsolatePool {
final List<Isolate> _isolates = [];
Future<void> initialize({int count = 4}) async {
for (int i = 0; i < count; i++) {
final isolate = await Isolate.spawn(_worker, i);
_isolates.add(isolate);
}
}
static void _worker(int id) {
print('Isolate $id started');
// Логика worker-изолята
}
}
4. Коммуникация между изолятами:
// Двусторонняя коммуникация через порты
Future<SendPort> createTwoWayCommunication() async {
final receivePort = ReceivePort();
await Isolate.spawn(
_isolateEntry,
receivePort.sendPort,
);
// Получаем порт для отправки сообщений в изолят
final sendPortToIsolate = await receivePort.first as SendPort;
// Создаем порт для получения ответов
final responsePort = ReceivePort();
sendPortToIsolate.send({
'message': 'Hello from main isolate',
'replyTo': responsePort.sendPort,
});
return sendPortToIsolate;
}
5. Важные ограничения и best practices:
- Изоляты не разделяют память, все данные должны быть сериализуемы
compute()не подходит для задач, требующих постоянной коммуникации- Для UI-обновлений из изолята используйте
IsolateNameServerилиStreamControllerсStreamBuilder - Избегайте создания большого количества изолятов (обычно 2-4 на CPU core)