Как стать автором
Обновить

Комментарии 10

Идея хорошая и правильная.
Но реализовать это правильно практически невозможно из за обилия подводных камней.

1) веб, нам ведь нужны будут сервайс/веб вокеры, раз асинк не годится, для веба он тем более не подойдет.

2) количеством выделяемых изолятов надо тонко управлять, ставя в очередь задания, коим не хватило места (в акведуке на бэке, например, по изоляту на каждые два ядра).

3) объекты между изолятами не копируются, их сериализация/десериализация в двоичные данные и обратно не та вещь, которой можно принебрегать. Также отсюда растут весьма неприятные баги, которые периодически фиксят (например тот же баг, когда enum в мейн эвент лупе не соответсвует enum'у в изоляте).

Для себя я вижу решение только оставить БЛоКи в покое в основном изоляте, а оперировать изолятами и тяжелой обработкой уже точечно в слое бизнес логики.

Пользуясь случаем порекламирую библиотеки замечательных разработчиков и моих друзей, которые могут помочь вам в этом нелегком деле)))
pub.dev/packages/worker_manager
pub.dev/packages/computer

PS: если проектировать архитектуру для общения с изолятами и подобной изолированости — может вам стоит отказаться от BLoC'а в сторону EventBus?
Сможете рассматривать каждый изолят как отдельный микросервис, а шину как месседж брокер. Pub/Sub гораздо проще управлять решая подобные проблемы. Но это может оказаться всеже слишком избыточным для большинства не самых сложных приложений.

  1. Не всем нужен веб. Да и что, людям перестать пользоваться compute-ом, ведь он тоже не работает в вебе)

  2. Все блоки работают в одном изоляте. Это решает сразу много проблем, к примеру не нужно ломать голову над тем, как между несколькими изолятами построить коммуникацию, или над тем, сколько изолятов запускать

  3. Я провёл несколько внутренних тестов, в результате которых выяснил, что передача данных между изолятами занимала около 5% всего остального времени. В тесте я передавал большое количество данных в виде строки, которые потом парсились и маппились внутри изолята, и передавались обратно. Сценарий получился весьма похожим на реальный кейс. А сравнивал я с тем же самым тестом, который был запущен в одном потоке

Ещё раз повторю, каждый может использовать инструмент по вкусу. Если тебе удобнее самому выносить тяжеловесные задачи, то пожалуйста! Но кому-то точно будет удобнее использовать мой вариант

  • compute-ом, ведь он тоже не работает в вебе)


Работает, там он выполняет асинхронную операцию
А также существуют кондишен импорты и веб/сервайс вокеры.

  • Все блоки работают в одном изоляте. Это решает сразу много проблем, к примеру не нужно ломать голову над тем, как между несколькими изолятами построить коммуникацию, или над тем, сколько изолятов запускать


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

  • Я провёл несколько внутренних тестов...

Поздравляю, потерял 5% ресурсов на копирование и кучу оперативной памяти на поддержание изолята, ничего с этого не выиграв)

Еще раз повторю - пользуйтесь всем чем хотите на свое усмотрение, но не надо вводить людей в заблуждение. А лучше поймите как работает эвент луп и все ваши "проблемы" как рукой снимет.

Ладно, я уже имел опыт дискуссий с тобой, поэтому не буду тратить ни свое время, ни твое время, ни время возможного читателя.

Всего доброго

а особенность его в том, что он работает в отдельном Isolate
— т.е. метод onEventRecived работает в отдельном изоляте так? — ну в принципе полезненько )), но не достаточно что бы (к примеру) уйти от ставшего неким стандартом-де-факто flutter_bloc… — вот если бы ваш пакет наделял эту реализацию такой фичей как обработка ивентов в отдельном изоляте — тогда да, я бы заюзал — ибо есть пара мест в коде, где сейчас используется compute в моих bloc

Болки, как и все, что создано или запущено в isolatedFunc, как раз и работают в отдельном изоляте)

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

Наверное, стоит добавить в лимиты на использование EventChannel
Так как это не работает
Подобные ситуации описивались тут

example
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 для них уже по умолчанию перенаправляется в изолят

Прочитать об этом больше вы можете в документации пакета

Надеюсь авторы этой библиотеки позаботились об оптимизации создания изолятов и переиспользуют какой то пулл для этого… Ибо будет очень печально если на каждый объект блока будет создаваться отдельный изолят. А вообще не вижу проблем для сложных операций внутри обычного блока выносить логику в отдельный изолят.

Все блоки работают в одном изоляте. К сожалению или к счастью, очень сложно сделать так, чтобы они работали в нескольких. Там появляются проблемы с коммуникацией между этими изолятами. Ведь не всегда возможно разделить приложение на несколько независимых частей, чтобы эти части запустить в разных изолятах

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории