Возможно, я неправильно представляю себе «Изолятор» и «Будущее». Пожалуйста, помогите мне разобраться. Вот мое понимание обоих предметов.
Изолировать: Изолирует запускает код в собственном цикле событий, и каждое событие может запускать более мелкие задачи во вложенной очереди микрозадач.
Будущее: будущее используется для представления потенциального значения или ошибки, которые будут доступны в какой-то момент в будущем.
Мои заблуждения:
В документе говорится, что у Isolate есть собственный цикл? Я чувствую, что для меня имеет больше смысла иметь собственную очередь событий, я ошибаюсь?
Future работает асинхронно на основном Isolate? Я предполагаю, что будущая задача действительно была помещена в конец очереди событий, поэтому, если она будет выполняться в цикле в будущем. Поправьте меня если я ошибаюсь.
Зачем использовать Isolate, когда есть будущее? Я видел несколько примеров использования Isolate для выполнения некоторых сложных задач вместо Future. Но почему? Для меня это имеет смысл только тогда, когда future выполняется асинхронно в основной изолированной очереди.
Future - это дескриптор, который позволяет вам получать уведомления о завершении асинхронного выполнения.
Асинхронное выполнение использует очередь событий, и код выполняется одновременно в одном потоке.
https://webdev.dartlang.org/articles/performance/event-loop
Код Dart по умолчанию выполняется в корневом изоляторе.
Вы можете запустить дополнительные изоляты, которые обычно выполняются в другом потоке.
Изолят может быть загружен либо из того же кода Dart, с которого был запущен корневой изолятор (с другой точкой входа, чем main()https://api.dartlang.org/stable/2.0.0/dart-isolate/Isolate/spawn.html), либо с другим кодом Dart (загруженным из некоторого файла Dart или URL https://api.dartlang.org/stable/2.0.0/dart-isolate/Isolate/spawnUri.html).
Изоляты не имеют общего состояния и могут обмениваться данными только с помощью передачи сообщений (SendPort / ReceivePort). У каждого изолята своя очередь событий.
https://webdev.dartlang.org/articles/performance/event-loop
позволяет ли дарт нам иметь основной поток и фоновый поток, как это делает Java?
В Dart действительно нет тем. Изоляторы выполняются в разных потоках ОС, но они сильно отличаются от потоков Java (без общего состояния).
Ага, как я объяснил в первом абзаце. Код выполняется в однопоточном режиме (без дополнительных изоляторов), и код синхронизации всегда выполняется до конца перед выполнением другого обратного вызова.
Когда вы говорите, что изоляторы работают в другом потоке ОС, означает ли это, что каждый изолятор имеет свой собственный цикл событий, очередь событий и очередь микрозадач?
Да, как уже упоминалось в моем ответе.
Isolate можно сравнить с Thread, даже если dart не является многопоточным. У него действительно есть собственная память и цикл обработки событий, когда Futures использует одну и ту же память.
Dart is able to spawn standalone processes, called Isolates (web workers in dart2js), which do not share memory when the main program, but are able to asynchronously, in another process (effectively a thread of sorts) is able to do computations without blocking the main thread.
Будущее запускается внутри изолята, который его назвал, а не обязательно основного изолята.
Я рекомендую этот статья, у которого есть лучшее объяснение, чем у меня.
Одним предложением мы могли бы сказать:
Изолирует: Dart является однопоточным, но он может выполнять многопоточную работу с использованием Isolates (многие процессы).
Будущее: Future - это результат, который возвращается, когда дротик завершает асинхронную работу. Работа обычно выполняется в этом однопоточном режиме.
Isolate запускает код Dart в одном потоке. Синхронный код вроде
print('hello');
запускается немедленно и не может быть прерван.
Isolate также имеет цикл событий, который он использует для планирования асинхронных задач. Асинхронность не означает, что эти задачи выполняются в отдельном потоке. Они по-прежнему работают в одном потоке. Асинхронный просто означает, что они запланированы на более позднее время.
Цикл событий запускает задачи, запланированные в так называемой очереди событий. Вы можете поместить задачу в очередь событий, создав такое будущее:
Future(() => print(hello));
Задача print(hello) будет запущена, когда другие задачи, стоящие перед ней в очереди событий, будут завершены. Все это происходит в одном потоке, то есть в одном изоляте.
Некоторые задачи не сразу добавляются в очередь событий, например
Future.delayed(Duration(seconds: 1), () => print('hello'));
который добавляется в очередь только после задержки в одну секунду.
Пока что все, о чем я говорил, делается в одной ветке, в том же Isolate. Однако некоторая работа может фактически выполняться в другом потоке, например операции ввода-вывода. Об этом позаботится основная структура. Если в основном потоке Isolate было выполнено что-то дорогостоящее, например чтение с диска, приложение заблокировалось бы до его завершения. Когда операция ввода-вывода завершается, будущее завершается, и обновление с результатом добавляется в очередь событий.
Если вам нужно самостоятельно выполнить операции с интенсивным использованием ЦП, вы должны запустить их на другом изоляте, чтобы это не приводило к зависанию вашего приложения. Свойство вычислить для этого хорошо. Вы по-прежнему используете future, но на этот раз future возвращает результат из другого Isolate.
Можно ли получать данные из изолята без ReceivePort и SendPort? Как, например, сохранить полученные данные в уже существующую переменную?
@ IvánYoed, я на самом деле не пробовал, но теоретически это не должно работать, поскольку изоляты не разделяют память. Однако, если у вас это сработает, я хотел бы увидеть ваш пример.
Недавно я разместил вопрос по этому поводу и получил хороший ответ. Может это вас интересует stackoverflow.com/q/67181838/13766744
@ IvánYoed, спасибо!
Изоляты подобны нитям. Фьючерсы - нет. Поэтому, если у вас есть дорогостоящие вычисления, Future по-прежнему будет блокировать пользовательский интерфейс, а Isolate - нет.