LINUX.ORG.RU

История изменений

Исправление Legioner, (текущая версия) :

У async/await есть небольшой, но оверхед

Давай сравнивать разные подходы.

Если мы используем потоки ОС, то в оверхед уходят:

  1. Стеки потоков. Условно 8 МБ виртуальной памяти, используемая память с гранулярностью в условные 4 КБ. Т.е. если мой поток реально кушает 20 байтов на стеке и ему этого хватает, то всё равно ОС ему выделит 4 КБ. Также в оверхед уходит сохранение/восстановление кучи регистров и переключение между режимом пользователя и ядра. Это считается самым большим оверхедом.

  2. Зелёные потоки, на примере Го. Со стеком тут всё примерно так же. Также глубокие стеки вызывают перерасход памяти, даже если они не используются. К примеру у нас энтерпрайз, и от начала потока до нашего реального метода проходит 500 вызовов всяких фреймворков. И в каждом потоке эти 500 вызовов будут дубликатами висеть и от этого никак не избавиться.

  3. async/await. Тут перерасхода никакого по сути. Идёт замыкание исключительно с нужными данными, пара указателей. Задача может занимать считанные десятки байтов, вне зависимости от того, сколько вызовов было потрачено, пока к ней дошло управление.

  4. Ручная state-машина. Ну по сути это самый оптимальный вариант. Причём async/await в идеале в неё и превращается.

Можно обвинять async/await в неудобной модели для программиста и я первый тут поддержу. Читать запутанный async/await-код может быть сложно. Научиться async/await ещё сложней. Лично я за зелёные потоки, как оптимальная середина - и для программиста всё просто как два рубля, и по производительности приемлемо. Но всё равно я считаю, что async/await (или на коллбеках алгоритмы) самые оптимальные по производительности. Хоть на удалённый сервер, хоть на локалхост, какая разница, всё равно тебе нужно организовывать управление соединениями.

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

Конечно лоб расшибить всегда можно. Но в любом случае твой вариант лучше, чем код-лапша, когда методы в сотни строк накопипасчены, что-то там рандомно меняется. Уж лучше паттерны.

Исходная версия Legioner, :

У async/await есть небольшой, но оверхед

Давай сравнивать разные подходы.

Если мы используем потоки ОС, то в оверхед уходят:

  1. Стеки потоков. Условно 8 МБ виртуальной памяти, используемая память с гранулярностью в условные 4 КБ. Т.е. если мой поток реально кушает 20 байтов на стеке и ему этого хватает, то всё равно ОС ему выделит 4 КБ. Также в оверхед уходит сохранение/восстановление кучи регистров и переключение между режимом пользователя и ядра. Это считается самым большим оверхедом.

  2. Зелёные потоки, на примере Го. Со стеком тут всё примерно так же. Также глубокие стеки вызывают перерасход памяти, даже если они не используются. К примеру у нас энтерпрайз, и от начала потока до нашего реального метода проходит 500 вызовов всяких фреймворков. И в каждом потоке эти 500 вызовов будут дубликатами висеть и от этого никак не избавиться.

  3. async/await. Тут перерасхода никакого по сути. Идёт замыкание исключительно с нужными данными, пара указателей. Задача может занимать считанные десятки байтов, вне зависимости от того, сколько вызовов было потрачено, пока к ней дошло управление.

  4. Ручная state-машина. Ну по сути это самый оптимальный вариант. Причём async/await в идеале в неё и превращается.

Можно обвинять async/await в неудобной модели для программиста и я первый тут поддержу. Читать запутанный async/await-код может быть сложно. Научиться async/await ещё сложней. Лично я за зелёные потоки, как оптимальная середина - и для программиста всё просто как два рубля, и по производительности приемлемо. Но всё равно я считаю, что async/await (или на коллбеках алгоритмы) самые оптимальные.

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

Конечно лоб расшибить всегда можно. Но в любом случае твой вариант лучше, чем код-лапша, когда методы в сотни строк накопипасчены, что-то там рандомно меняется. Уж лучше паттерны.