Обновить
3
0
Сергей Иванов@Lutvuk

Пользователь

Отправить сообщение
Я, возможно, не самый удачный пример привел, как можно оборвать цепочку async. Ну так это и не единственный из доступных вариантов, выбирайте подходящий для вашей задачи. Это ведь вы утверждаете, что если в программе на нижнем уровне завелся async, то все до самого неба должно быть в него завернуто? Нет такой необходимости, делайте как вам удобно и подходит для эффективного решения задачи.
Конечно, до тех пор пока не завершится readDataFromFS(/*… */). Вы полагаете await делает что-то иное?
Известно, что await можно использовать только внутри функций или блоков async

Верно.
, а это значит, что если у вас самый нижний уровень API асинхронный, то придется использовать async/await практически везде, даже там, где оно очевидно не нужно.

А это уже ложное утверждение. Асинхронная функция возвращает промис, завершение работы которого можно дождаться и без использования await. Никто не запрещает написать, например, так:
function getData() {
    if (!globalCache.data) {
        globalCache.data = resolve(readDataFromFS(/* ... */));
    }

    return globalCache.data
}

И все, никакой «вирус» async не распространяется выше по уровням кода.
Именно поэтому примеры кода из статьи годятся, только чтобы оценить стоимость вызова функции обернутой в async/await. Но никак не годятся для оценки возможной выгоды от применения этих конструкций на практике. Поэтому вывод о применимости асинхронного API базируется на не верной предпосылке выведенной из некорректного применения конструкций языка.

Вот это вот утверждение:
Интересно, что там где использование async/await наиболее распространено (и даже пропагандируется), издержки на асинхронный вызов просто запредельные.

Иллюстрируется примерами с некорректным применением этих самых async/await. Если я правильно понял уважаемого автора balajahe, то он своими примерами хотел проиллюстрировать случай когда у нас нужные данные уже однажды получены и закешированы и мы уже можем получить данные быстро. Но сопроводил это не корректным использованием конструкций async/await. Даже если f функция какого-то внешнего API, нельзя ее вызывать в цикле и тут же в той же итерации ожидать ее завершения, приходится сначала породить необходимое количество промисов и только после этого дожидаться их завершения, чтобы дальше что-то делать с результатами вычислений.

Async/await по сути синтаксический сахар для запуска функции в отдельном потоке, придуманный чтобы кода поменьше писать. Но правильно применять параллелизм в решении задачи все еще задача программиста.

Извините, в интернете кто-то не прав.

Ваш код:
for (let i = 0; i < 1_000_000_000; i++) {
        j += await f(i)
}

Будет всегда работать медленнее синхронного кода вне зависимости от сложности функции f. Итерации цикла исполняются последовательно. В каждой итерации ожидается (avait) завершение вызова f и только после этого выполняется переход к следующей итерации. Т.е. тут просто код спроектирован не подходящим образом для использования асинхронных функций.

Чтобы увидеть выгоду от асинхронных функций, нужно чтобы выполнилось два условия:
  1. Сначала породить стрим/список/массив (или что там вам по задаче больше подходит) промисов, а только потом их ждать и что-то делать с результатами.
  2. Убедиться, что время выполнения функции существенно больше времени необходимого на старт потока и синхронизацию.

В ваших тестовых примерах не выполнено ни одно из этих условий — каждый вызов асинхронной функции выполняется строго после завершения предыдущего и одна операция деления намного быстрее затрат на синхронизацию.

Информация

В рейтинге
Не участвует
Откуда
Зеленоград, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность