Как создать два потока в Dart в контексте Flutter?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Для создания независимых потоков выполнения в Dart/Flutter используются Изоляты (Isolates). Они представляют собой отдельные задачи с собственным выделенным пространством памяти, что предотвращает проблемы с конкурентным доступом к данным и блокировку основного потока (UI-потока).
Существует несколько способов создания и взаимодействия с изолятами:
-
Isolate.spawn(): Самый низкоуровневый способ создания изолята. Требует передачи функции верхнего уровня или статического метода класса для выполнения в новом изоляте и порта для обмена сообщениями.import 'dart:isolate'; // Функция, выполняющаяся в изоляте void isolateEntry(SendPort sendPort) { // Выполняем какую-то долгую операцию int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } // Отправляем результат обратно основному изоляту sendPort.send(result); } void main() async { ReceivePort receivePort = ReceivePort(); // Создаем новый изолят Isolate isolate = await Isolate.spawn(isolateEntry, receivePort.sendPort); // Слушаем сообщения от изолята receivePort.listen((message) { print('Результат из изолята: $message'); // Завершаем изолят после получения сообщения isolate.kill(); }); print('Основной поток продолжает работу...'); } -
compute(): Упрощенная функция из пакетаflutter/foundation, которая используетIsolate.spawn()под капотом. Идеально подходит для простых фоновых задач, не требующих сложного взаимодействия с изолятом.import 'package:flutter/foundation.dart'; // Функция, выполняющаяся с помощью compute int heavyComputation(int limit) { int result = 0; for (int i = 0; i < limit; i++) { result += i; } return result; } void main() async { print('Начинаем тяжелые вычисления в фоне...'); // Выполняем функцию в отдельном изоляте int result = await compute(heavyComputation, 1000000000); print('Результат вычислений: $result'); print('Основной поток продолжает работу после вычислений.'); } -
Isolate.spawnUri(): Используется для запуска кода из отдельного файлаdartв новом изоляте.
Взаимодействие между изолятами:
Изоляты обмениваются данными только путем передачи сообщений через экземпляры SendPort и ReceivePort. Это атомарные операции, не требующие блокировок или других механизмов синхронизации.
SendPort: Используется для отправки сообщений из одного изолята в другой.ReceivePort: Используется для прослушивания входящих сообщений.
При передаче объектов между изолятами, они должны быть "передаваемыми" (transferable), что включает в себя:
- Простые типы данных (int, double, String, bool)
- Списки и мапы, содержащие передаваемые типы
- Некоторые специфические для Flutter типы, которые могут быть сериализованы
Объекты, не являющиеся передаваемыми, будут скопированы, а их последующие изменения в одном изоляте не отразятся в другом.
Ключевые моменты:
- Изоляты не могут напрямую обращаться к памяти друг друга.
- Изоляты не имеют доступа к общему состоянию, включая переменные, классы и виджеты основного изолята (UI-потока).
- Общение между изолятами происходит асинхронно.
- При работе с изолятами в Flutter важно правильно управлять их жизненным циклом (например, использовать
isolate.kill()при необходимости).
Использование изолятов позволяет выполнять длительные или ресурсоемкие операции в фоне, предотвращая зависание пользовательского интерфейса и обеспечивая плавность работы приложения.