1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-Async.md 15 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Различия между Dart async/await и Kotlin suspend. Также рассмотрим "Easter egg" Flutter в ColorOS Oppo.

В одной из наших предыдущих бесед [«Могут ли Kotlin-coroutines полностью заменить потоки?»] была затронута тема вопроса: Какие различия существуют между Dart async/await, Kotlin suspend и асинхронностью в JavaScript?

На самом деле, как Dart async/await, так и Kotlin suspend являются просто синтаксическим сахаром, то есть способом представления кода таким образом, чтобы он был более понятным и структурированным. В этом плане они не имеют различий — это всего лишь синтаксический сахар.

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

В данной статье мы кратко обсудим синтаксический сахар и закончим рассказом об "Easter egg" Flutter в ColorOS Oppo.

Dart async/await

Вы наверняка знаете, что в Dart async/await на самом деле работает через известный вам объект Future. Например, вот пример использования async/await:

Future<int> doSomething() async {
  whatTF();

  var x = await someIntFuture();
  return godGG(x);
}

На практике этот код эквивалентен следующему:

Future<int> foo() {
  whatTF();

  return someIntFuture().then((x) {
    return godGG(x);
  });
}

Здесь await фактически преобразуется в вызов метода Future.then.В реализации Future, которая находится в файле future_impl.dart, используется приватный метод _thenAwait, который служит для реализации синтаксического сахара await. Этот метод регистрирует новый Future и создаёт _FutureListener.=

Основное отличие заключается в том, что then проверяет корректность переданной функции ошибок (onError) заранее, тогда как её вызов осуществляется в модуле Dart sdk/lib/_internal/vm/lib/async_patch.dart:

Основная функция создания асинхронных колбэков заключена в методе _createAsyncCallbacks. Второй метод _await(Object? object) принимает объект типа Object?, так как все видимые типы в Dart являются подтипами Object, а все функциональные типы — подтипами Function. При этом сам Function также является типом Object:

int doSomeThing() {
   return 1;
}

void main() {
	// выводит true
    print('${doSomeThing is Object}');
}

Для более подробного ознакомления с типами см.: https://juejin.cn/post/6968369768596242469

А вот как показано ниже, на самом деле методы then и thenAwait имеют мало различий. То есть реализация then и await практически одинакова. Различия между stateThenAwait, stateThen и stateThenOnError заключаются в небольших отличиях в стеках трассировки:

Ого, а вы заметили, что у then и _thenAwait есть состояние? Почему же в объекте Future есть состояние? Это можно объяснить с помощью стеков трассировки:Система выполнения использует awaiter stack trace, чтобы улучшить отслеживание стека. Каждый awaiter представляет собой замыкание или поддерживаемую приостановкой async функцию, и каждый awaiter состоит из пары (замыкание, следующий кадр):

  • Когда будущее этого awaitera завершается, вызывается замыкание
  • А следующий — это объект, представляющий следующего awaitera, как если бы это был связанный список

Из диаграммы путей через Awaiter Stack Traces видно, что в процессе существует ключевой объект _SuspendState.

Увидев _SuspendState, вы можете вспомнить suspend в Kotlin? Верно, этот объект отвечает за управление состоянием приостановленной асинхронной операции внутри Dart:

Более абстрактно:

  • _SuspendState._initAsync создаёт экземпляр _Future<T>, который используется как результат async функции, и этот экземпляр хранится в переменной :suspend_state C++ виртуальной машины

  • Затем из _SuspendState._await возвращаются _SuspendState._returnAsync, _SuspendState._returnAsyncNotFuture и _SuspendState._handleException, которые используются как результат async функции.- При первом вызове _SuspendState._await создаются замыкания для then и error, которые восстанавливают выполнение асинхронной функции через _resume. Если параметр await является Future, то _SuspendState._await добавляет замыкания then и error к этому Future, в противном случае он просто планирует микротаск для продолжения выполнения приостановленной функции. Речь идет о том, что в файле sdk/lib/_internal/vm/lib/async_patch.dart реализован метод _SuspendState._await, который отвечает за выполнение выражения await.Иллюстрация

Кроме того, обработка исключений также осуществляется через метод _handleException внутри _SuspendState. Можно заметить, что вся реализация Future для async/await основана на состоянии машины _SuspendState, которая обеспечивает возможность приостановки и восстановления.

Иллюстрация

Если объяснять реализацию синтаксического сахара для async/await, то это просто Future / then. На самом деле, Dart преобразует его в машину состояний для управления выполнением функций и приостановками в await. Это позволяет использовать синхронный стиль для написания асинхронного кода, повышая его читаемость.

Kotlin Suspend

В Kotlin suspend-функции также могут быть приостановлены и возобновлены без блокировки выполняющего их потока. Они представляют собой синтаксический сахар, позволяющий разработчику писать асинхронный код в синхронном стиле.

Добавление ключевого слова suspend фактически сообщает компилятору, что данная функция может быть приостановлена.

При обработке suspend-функций компилятором они преобразуются в соответствующую внутреннюю реализацию, известную как CPS (Continuation Passing Style). Основной момент здесь — продолжение (continuation), которое хранит состояние функции, локальные переменные и контекст выполнения.Продолжение обычно сохраняет ссылку на продолжение вызывающей стороны, поэтому они образуют цепочку продолжений, которую можно использовать для генерации трассировки стека.

Например, простое описание suspend-функции заключается в том, что она переопределяется как процесс, принимающий параметр типа Continuation:

suspend fun getUser(): User?
suspend fun setUser(user: User)
suspend fun checkAvailability(flight: Flight): Boolean

fun getUser(continuation: Continuation<User?>): Any?
fun setUser(user: User, continuation: Continuation<Unit>): Any
fun checkAvailability(
flight: Flight,
continuation: Continuation<Boolean>): Any

На практике это выглядит примерно так:

// Преобразование до
suspend fun fetchData(): String {
    println("Начало получения данных")
    val result = networkRequest()
    println("Данные получены: $result")
    return result
}

suspend fun networkRequest(): String {
    delay(1000)
    return "Привет, мир!"
}

Можно заметить, что компилятор Kotlin генерирует сопрограммы, аналогичные концепции машины состояний, которая отслеживает состояние выполнения функции, например, используя метку для отслеживания места возобновления.

Поэтому, с точки зрения дизайна, сопрограммы в Kotlin представляют собой сочетание машин состояний и передачи управления, что позволяет реализовать модель, позволяющую приостанавливать и возобновлять выполнение.

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

  • Корутины Kotlin на JVM действительно используют многопоточную модель и поддерживают переключение между потоками.
  • Корутины Dart используют однопоточную модель циклического опроса, а много потоковых изолятов и потоков Thread не являются абсолютной парой один к одному.

OPPO ColorOS

Наконец, немного отступлю от темы. Вчера мне попалась статья Алекса в группе, где он делится скриншотами вывода ColorOS Живого острова во время работы. Можно заметить, что UI-рендеринг ColorOS Живого острова реализован с помощью Flutter:

Интересно отметить, что ранее на платформе разработчиков OPPO (разработка для OPPO) также были представлены логические данные экрана "Живого" острова. Тогда можно было видеть, что эти данные тоже основаны на Flutter:

Однако стоит отметить, что верхний уровень или приложения, использующие этот подход, могут не быть написаны на Dart, а использовать свои собственные шаблоны для поддержки этого метода. Это очень похоже на подход WeChat Mini Programs Skyline:

Поэтому это ещё одна малоизвестная сторона Flutter.## Дополнительные материалы

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master