Комментарии 10
Но реализовать это правильно практически невозможно из за обилия подводных камней.
1) веб, нам ведь нужны будут сервайс/веб вокеры, раз асинк не годится, для веба он тем более не подойдет.
2) количеством выделяемых изолятов надо тонко управлять, ставя в очередь задания, коим не хватило места (в акведуке на бэке, например, по изоляту на каждые два ядра).
3) объекты между изолятами не копируются, их сериализация/десериализация в двоичные данные и обратно не та вещь, которой можно принебрегать. Также отсюда растут весьма неприятные баги, которые периодически фиксят (например тот же баг, когда enum в мейн эвент лупе не соответсвует enum'у в изоляте).
Для себя я вижу решение только оставить БЛоКи в покое в основном изоляте, а оперировать изолятами и тяжелой обработкой уже точечно в слое бизнес логики.
Пользуясь случаем порекламирую библиотеки замечательных разработчиков и моих друзей, которые могут помочь вам в этом нелегком деле)))
pub.dev/packages/worker_manager
pub.dev/packages/computer
PS: если проектировать архитектуру для общения с изолятами и подобной изолированости — может вам стоит отказаться от BLoC'а в сторону EventBus?
Сможете рассматривать каждый изолят как отдельный микросервис, а шину как месседж брокер. Pub/Sub гораздо проще управлять решая подобные проблемы. Но это может оказаться всеже слишком избыточным для большинства не самых сложных приложений.
Не всем нужен веб. Да и что, людям перестать пользоваться
compute
-ом, ведь он тоже не работает в вебе)Все блоки работают в одном изоляте. Это решает сразу много проблем, к примеру не нужно ломать голову над тем, как между несколькими изолятами построить коммуникацию, или над тем, сколько изолятов запускать
Я провёл несколько внутренних тестов, в результате которых выяснил, что передача данных между изолятами занимала около 5% всего остального времени. В тесте я передавал большое количество данных в виде строки, которые потом парсились и маппились внутри изолята, и передавались обратно. Сценарий получился весьма похожим на реальный кейс. А сравнивал я с тем же самым тестом, который был запущен в одном потоке
Ещё раз повторю, каждый может использовать инструмент по вкусу. Если тебе удобнее самому выносить тяжеловесные задачи, то пожалуйста! Но кому-то точно будет удобнее использовать мой вариант
compute
-ом, ведь он тоже не работает в вебе)
Работает, там он выполняет асинхронную операцию
А также существуют кондишен импорты и веб/сервайс вокеры.
Все блоки работают в одном изоляте. Это решает сразу много проблем, к примеру не нужно ломать голову над тем, как между несколькими изолятами построить коммуникацию, или над тем, сколько изолятов запускать
И создает новую, в виде дополнительного расхода ресурсов и копирования зависимостей между изолятами
Я провёл несколько внутренних тестов...
Поздравляю, потерял 5% ресурсов на копирование и кучу оперативной памяти на поддержание изолята, ничего с этого не выиграв)
Еще раз повторю - пользуйтесь всем чем хотите на свое усмотрение, но не надо вводить людей в заблуждение. А лучше поймите как работает эвент луп и все ваши "проблемы" как рукой снимет.
а особенность его в том, что он работает в отдельном Isolate— т.е. метод onEventRecived работает в отдельном изоляте так? — ну в принципе полезненько )), но не достаточно что бы (к примеру) уйти от ставшего неким стандартом-де-факто flutter_bloc… — вот если бы ваш пакет наделял эту реализацию такой фичей как обработка ивентов в отдельном изоляте — тогда да, я бы заюзал — ибо есть пара мест в коде, где сейчас используется compute в моих bloc
Так как это не работает
Подобные ситуации описивались тут
import 'dart:async';
import 'dart:isolate';
import 'package:battery/battery.dart';
import 'package:flutter/material.dart';
import 'package:isolate_bloc/isolate_bloc.dart';
Future<void> main(List<String> arguments) async {
await initialize(isolatedFunc);
runApp(
MaterialApp(
home: IsolateBlocProvider<BatteryBloc, int>(
child: BatteryScreen(),
),
),
);
final Battery _battery = Battery();
_battery.onBatteryStateChanged.distinct().listen((event) {
print('Main isolate $event');
});
}
class BatteryScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Battery'),
),
body: Center(
child: IsolateBlocListener<BatteryBloc, int>(
listener: (context, state) => print('New bloc state: $state'),
child: IsolateBlocBuilder<BatteryBloc, int>(
builder: (context, state) => Text('Battery level: $state'),
),
),
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
heroTag: 'Refresh',
onPressed: () =>
context.isolateBloc<BatteryBloc, int>().add(CountEvent.refresh),
child: const Icon(Icons.refresh),
),
],
),
);
}
}
Future<void> isolatedFunc() async {
register(create: () => BatteryBloc());
}
class BatteryBloc extends IsolateBloc<CountEvent, int> {
BatteryBloc() : super(0) {
_streamSubscription = _battery.onBatteryStateChanged.listen((event) {
print('${Isolate.current} $event');
});
}
final Battery _battery = Battery();
StreamSubscription _streamSubscription;
@override
Future<void> onEventReceived(CountEvent event) async {
final batteryLevel = await _battery.batteryLevel;
emit(batteryLevel);
}
@override
Future<void> close() {
_streamSubscription.cancel();
return super.close();
}
}
enum CountEvent {
refresh,
}
Спасибо за прекрасный пример!
В функцию initialize
можно передать список MethodChannel-ов, которые будут перенаправляться в изолят. К примеру вы можете загружать ассеты в блоке, так как MethodChannel для них уже по умолчанию перенаправляется в изолят
Прочитать об этом больше вы можете в документации пакета
Все блоки работают в одном изоляте. К сожалению или к счастью, очень сложно сделать так, чтобы они работали в нескольких. Там появляются проблемы с коммуникацией между этими изолятами. Ведь не всегда возможно разделить приложение на несколько независимых частей, чтобы эти части запустить в разных изолятах
Flutter. Как прокачать ваш BLoC