Ой. Нет репо внутри транзакции или транзакции внутри репо. Есть атомарная операция. В статье она реализуется через транзакцию БД, но ведь транзакция БД и атомарная бизнес-операция - не одно и то же.
Меня несколько смутило использование контекста бизнес-операции для обмена данными между интерфейсами репо (я говорю о реализации в статье, где Database реализует и CarRepository и Transactor). Отсюда - предложение из моего первого комментария.
В ветке ниже (где QueryExecutor)@andrdru, фактически, предложил тот же вариант - передавать в замыкание работающий внутри транзакции экземпляр CarReporisotory.
У вас там хороший, развернутый комментарий. По нему у меня ощущение, что мы упираемся в какие-то идеологические, а не практические соображения.
Ведь подходы с контекстом и txRepo, в принципе, схожи. Внутри замыкания можно использовать ctx и txCtx, а можно - repo и txRepo. Транзакция в обоих случаях создаётся на уровне репо. И если управление транзакцией (интерфейс Transactor, реализуемый репо) пробрасывается выше - его ведь можно и, может, даже желательно прикрыть интерфейсом домена?
Так что, в принципе, всё сводится к тому как именно Transactor доступен выше уровня домена, и различию между
c.carRepo.GetCar(txCtx, id)
и
txRepo.GetCar(ctx, id)
Мне второй вариант кажется чуть более устойчивым (он даёт компилятору больше информации), но различие это не принципиально.
Контекст и так доступен в замыкании. Передавать его параметром нужно, если контекст изменяется. В варианте "замыкание получает экземпляр CarRepository, работающий внутри транзакции" это не нужно.
Копия (новый экземпляр, не тип) Database реализует уже объявленный интерфейс CarRepository, именно его я предлагаю передавать в замыкание.
Возможно, для conn придется использовать интерфейс, подобный приведенному ниже в комментариях QueryExecutor.
Ух. Не трогаем специалистов. Они молодцы и вообще справились.
Если вы намекаете на 32-битный unixtime — во-первых снимаю шляпу, во-вторых вы совершенно правы — такого рода ошибки решаются крайне сложно даже оригинальными разработчиками.
Я резко прокомментировал вот эти строки цитируемые в статье:
Программа была не такой большой, однако оказалась непостижимой. Её писали в стиле, отдававшем приоритет вычислительной эффективности, а не простоте чтения.
Почему резко прокомментировал? Работая с чужим кодом часто чувствуешь дискомфорт. Как раз вот это ощущение "казалась непостижимой". Причем дискомфорт этот никак не связан с качеством программы, скорее с тем, что абстракции, терминология, подход непривычны.
Есть соблазн объявить: "Ничего понять нельзя, плохой код, давайте перепишем". Не решить проблему, а просто отложить её решение, сбежать в зону комфорта.
И навык (именно навык) преодоления этого дискомфорта, умения сначала разобраться с тем, что другой разработчик ХОТЕЛ сделать и уже потом с тем, как он это делал и что у него получилось, мне кажется одним из самых недооцененных.
Дальше по тексту (цитата из цитаты из статьи):
Заметив, что из первой программы из-за её вылета нет выходных данных, она восприняла эту ситуацию как «все вклады равны 0». Разумеется, она должна была вести себя совершенно иначе. Но никто не знал, что она будет действовать так
Я понимаю почему написано именно так. Но всё равно "разумеется, она должна была" и "никто не знал, что она будет" в одном абзаце звучат странно. Как описание непостижимого черного ящика внутри черного ящика непостижимости.
Ощущение, что за пару десятилетий не нашлось ни одного человека, который бы заглянул туда из простого любопытства.
Я думаю, что эта самая "непостижимость", эмоциональная реакция, часто является ключевым фактором, из-за которого программа либо преждевременно переписывается (часто неудачно) либо живет слишком долго. Непостижимость ведет к неадекватной оценке существующего решения. И я против того, чтобы маскировать неадекватность оценки (одновременно завышенные ожидания и негативный отзыв) концепцией технического долга или гниения.
Мы говорим о разных вещах. Есть естественная смерть продукта — та самая промышленная археология. Когда ПО не компилируется, когда инжектор оказывается дешевле карбюратора. Когда логичнее купить новый автомобиль, чем поддерживать старый.
А есть — запланированное устаревание. Которое потребителю обходится дороже в любом случае, а в случае ПО — еще и умножает риски на порядок. Потому что это не покупка новой модели автомобиля, а её разработка с нуля, причем людьми, до этого занимавшихся оросительными системами, расклейкой афиш и игрой на скрипке. Которые сходу вам скажут, что автомобиль — дерьмо, потому что "дворники" не дают нормального орошения, сигнал какой-то скучный, а номерной знак с таким шрифтом и подачей ни одного билета не продаст.
Ну как не согласиться насчёт баланса?
Я немного не согласен с "меньше усилий чем сделать переделать".
Тут такая штука — в статье кроме смены поколений ПО (мы как-то слишком сейчас на ней сконцентрировались), есть еще банальная некомпетентность. Не та, где "соискатель не продемонстрировал знание современных парадигм проектирования" а намного более важная — способность разобраться в проблеме. Вот смотрите:
Программа была не такой большой, однако оказалась непостижимой. Её писали в стиле, отдававшем приоритет вычислительной эффективности, а не простоте чтения.
Что видите? Хреновую старую программу? А я вижу, что автор не умеет и не хочет читать чужой код. Существует в узком пространстве привычных шаблонных решений.
И, что НАМНОГО хуже — не имеет чёткого представления о предметной области.
Человек не понимает какую проблему решает программа, поэтому не может и не хочет разобраться в том, как она это делает. Отсюда уверенно накидывает о гнили, протухлости и прочей ерунде.
В финансовой сфере основные затраты и риски при разработке новой версии связаны с обучением разработчиков. Они косячат и будут косячить. Особенно если концентрируются на технологии, а не проблеме. И можно десятилетиями вкладывать в косяки обучение сотни тысяч в год, а можно использовать рабочее ПО до самой его естественной смерти и вложиться в косяки аврально, но один раз, для создания нового поколения. Тоже ведь баланс.
В статье речь идет о плановом устаревании. С точки зрения производителя — отличная штука. Но покупатель с этим не всегда согласен.
А что будет если нужно просуммировать длину ответа трех ПОСЛЕДОВАТЕЛЬНЫХ запросов? Где, скажем, url второго получаем из ответа первого, а url третьего — из второго?
Для того, чтобы записать, скажем такую странную штуку:
result = 0
for _ in range(3):
response = await client_get(url)
result += len(response.content)
url = response.content
придется использовать вложенность (которую чаще именуют callback hell'ом). Ну или вызовы asyncio.run в коде везде, где раньше случалось встретить await, превращая код в по-настоящему синхронный. И в любом случае — плохо читаемый.
Можно тысячу раз спросить "а на..., простите, зачем?!" глядя на цикл с await выше, но никак не "а что, собственно, этот код делает?". Чего, боюсь, не скажешь о коде, написанном с помощью описанного в статье подхода.
Хорошо, если удастся не превращать чистоту в фетиш
Да пожалуйста! Вот только не молитесь на неё.
Вы заметили как понятие чистоты из количественной характеристики (символы на блок кода) мутировало в абстракцию, по восприятию близкую к божественной непогрешимости?
Меня вот совсем не пугает фетишист, тихонько получающий удовольствие от процесса кодирования. Они обычно продуктивны.
Кто меня по-настоящему пугает — так это идеалист, постоянно находящийся в глубокой фрустрации и несущий из этой фрустрации свет. Обычно методом выжигания неверных.
Сначала человек страдает от того, что не получается найти решение положенного градуса святости. Потом паникует от того, что в выстраданное, сияющее решение нужно вносить коррективы. Месяцами тупит потому что картинка в голове не складывается. Потом годами занимается чем угодно, только не тем, чем нужно. Просто потому, что сложившаяся красивая картинка совершенно не соответствует решаемой задаче.
Меня до чертиков пугает фокус на чистоте кода и архитектуре вместо понимания проблемы. Не получается разобраться сходу? Сделай и потом отрефактори. Лучше понимая что нужно сделать. Лучше понимая как. Обычно у человека, хорошо понимающего ЧТО он делает, код как-то сам собой получается сопровождаемым.
Но нет же, как можно, что за профанация и богохульство, придет же технический долг и мы все умрем. Давайте лучше сразу подстрахуемся: триста земных поклонов каждый день, строгий пост (только best practices, ничего скоромного) и будем говорить только на латыни: "Давайте имплементируем дизайн-паттерны релевантные контексту скоупа карентовой бизнес-стори". Теперь уж точно ничего не сможет пойти не так — святая архитектура услышит наши молитвы и нас защитит, да будет она чиста вовеки.
Код — утилитарная штука. Инструмент, а не объект поклонения. Можно слепить из него арт-объект. Можно посоревноваться, замерить какой код будет выше, дальше или там сильнее. Раздвинуть границы. Можно, простите, даже дрочить на него. Соблюдая правила гигиены и выдерживая график. Но, блин, пожалуйста, пожалуйста, не надо в него веровать.
Почему веб-приложение тормозит и не держит нагрузку? <...> Ответ на поставленный вопрос кроется на более низком уровне — на уровне операционной системы. Чтобы ваше приложение держало нагрузку, необходимо пересмотреть его архитектурную концепцию таким образом, чтобы эффективно работать именно на этом уровне. Это привело к возникновению асинхронных веб-серверов.
Как-то так получается, что синхронный — дура, а асинхронный — молодец.
Пара (ок, чуть больше) замечаний:
Нагрузка и модель работы веб-сервера — не слишком связанные штуки. Синхронный веб-сервер далеко не обязательно медленнее асинхронного или хуже справляется с нагрузкой. Зависит от задачи.
Не совсем понятно при чем здесь ОС. Точнее совсем непонятно.
Синхронные сервера появились не потому, что "не изобрели" асинхронный. А потому, что асинхронный сервер писать и отлаживать тяжелее. И тяжелее контролировать использование ресурсов.
Те асинхронные сервера, о которых чаще говорим сейчас, начали развиваться для обработки медленных запросов (статика, большие файлы через медленное соединение) и поддержки большого количества открытых соединений (long polling, websockets ...).
Появившийся в процессе инструментарий (например, конструкции async/await) позволяет здорово облегчить реализацию бизнес-логики асинхронного веб-сервиса, но никак не ускорить его работу.
Спектр задач, решаемых асинхронными серверами, шире, чем у синхронных. Этим они сильны, а не могучей "архитектурной концепцией" или тем, что "веб-приложение не тормозит".
В текущем варианте — overengineering в чистом виде.
Техническая часть статьи сводится к тому, как силами всего трех дополнительных модулей и нескольких подключенных библиотек в Django-приложение можно встроить декларативный язык для описания stories. И что это дает некоторые преимущества при отладке бизнес-логики.
Сама реализация, ограничения, которые она накладывает на оптимизацию, технические проблемы, которые придется решать, полностью аналогичны тем, что встречаются при реализации GraphQL-сервера.
Сейчас, судя по приведенному коду, возможные проблемы не решаются никак.
Более того — решить их на уровне библиотеки так, чтобы разработчик мог сконцентрироваться на бизнес-логике, в текущей, синхронной, версии Django не получится.
где у кита жабры? Если это млекопитающее, то у него легкие (sic!)
Комментарий относится к первым двум абзацам статьи, где анализируется дизайн кита.
В них автор статьи приходит к выводу что дизайн — ужасен, потому что кит — не рыба. А еще кит — не хищник и вообще легаси. И нужно все переписать.
При том, что пятиминутного изучения domain'а (предметной области) должно было бы, чтобы понять, что рыба размером с кита просто задохнется. А хищник такого размера — умрет голодной смертью.
В воде содержание растворённого кислорода достигает 11 см³ на литр. В воздухе содержание кислорода равно 210 см³ на литр.
Для получения достаточного количества кислорода из воды нужно прокачивать через жабры большие её количества. Например, непрерывно двигаясь (как акулы). И еще больше увеличивая потребление кислорода.
Кит теплокровен — его подвижность не зависит от температуры. Большинство видов акул — нет. Для подогрева тела киту опять же нужны пища и кислород.
Для того, чтобы получить достаточное количество еды, крупной рыбы уже недостаточно. Как и крупнейшие виды акул, киты питаются планктоном. И рады бы рыбкой, да где ж её взять в таких количествах?
Киты были замечены на глубине до 3 километров. Акулы — до двух.
Возможно, MVP акулы и выглядит перспективнее, но мне кажется, что с ростом проекта разработчикам пришлось внести коррективы в то, что поначалу казалось таким очевидным.
Видимый плюс библиотеки — трейсбэки. Которые режутся стандартной библиотекой не без причины. Для получения трейсбека нужно держать в памяти стек, который корутиной (да больше никем) использоваться не будет.
Код из статьи, использующий стандартный asyncio, мне кажется понятнее и очевиднее кода, написанного с использованием Trio. Использование with вместо asyncio.wait совсем не понравилось. Но здесь дело вкуса.
Вообще для меня странно, что бенчмарк http сервера включает в себя какие-то запросы к базе. Тем более — к конкретной базе. Это почти автоматически означает, что мы меряем непонятно что.
Бенчмарки TechEmpower проводятся по семи сценариям. Есть и бенчмарк http сервера (plaintext). Он упоминается в статье, туда легче всего попасть. Фреймворки ссылаются именно на него. Там замеры делаются очень даже понятно чего, причем самой длинной линейкой.
Опишу ситуацию, в которой остальные, синтетические, бенчмарки полезны.
Скажем есть возможность, даже необходимость, сменить стек (фреймворк, язык программирования, всё, что душа пожелает). Собирать его по частям — ну очень утомительно. Вот 5 фреймворков, вот 3 клиента postgres, вот так (обещают) будет работать быстро, а вот так — идиоматичненько. А может использовать MySQL? Вот еще 2 клиента на выбор. И так по каждому пункту. И это если отбросить вообще неведомые вещи, которые хороший парень ну очень рекомендует.
Такая непрерывная фрустрация, когда информации много, тонешь. Рыться можно часами и сутками, а решение в итоге принимается с ощущением выбора наугад.
Синтетические бенчмарки дают готовый, подобранный другими людьми набор с четкими результатами (ну очень удобно, если есть требования по нагрузке). Помогает сузить стартовый набор вариантов, одновременно предлагая несколько работающих примеров использования.
Это аргумент в пользу того, чтобы научить приложения работать с одним соединением вместо пула, а не ругать актикс что они там считерили с соединенями.
Да!
Вальяжное вступление, возможно, сбивает с толку. Мне НРАВИТСЯ actix, я в восторге от того, насколько уместны, точны и осмысленны те технические решения, которые я увидел в коде.
В бенчмарках actix нет чита. Есть условие проведения бенчмарка — запросы к БД должны выполняться последовательно. В тексте я процитировал код, который может человеком, привыкшим к работе с пулом соединений, восприниматься как параллельный. Это не так.
Ой. Нет репо внутри транзакции или транзакции внутри репо. Есть атомарная операция. В статье она реализуется через транзакцию БД, но ведь транзакция БД и атомарная бизнес-операция - не одно и то же.
Меня несколько смутило использование контекста бизнес-операции для обмена данными между интерфейсами репо (я говорю о реализации в статье, где Database реализует и CarRepository и Transactor). Отсюда - предложение из моего первого комментария.
В ветке ниже (где QueryExecutor)@andrdru, фактически, предложил тот же вариант - передавать в замыкание работающий внутри транзакции экземпляр CarReporisotory.
У вас там хороший, развернутый комментарий. По нему у меня ощущение, что мы упираемся в какие-то идеологические, а не практические соображения.
Ведь подходы с контекстом и
txRepo
, в принципе, схожи. Внутри замыкания можно использоватьctx
иtxCtx
, а можно -repo
иtxRepo
. Транзакция в обоих случаях создаётся на уровне репо. И если управление транзакцией (интерфейс Transactor, реализуемый репо) пробрасывается выше - его ведь можно и, может, даже желательно прикрыть интерфейсом домена?Так что, в принципе, всё сводится к тому как именно Transactor доступен выше уровня домена, и различию между
c.carRepo.GetCar(txCtx, id)
и
txRepo.GetCar(ctx, id)
Мне второй вариант кажется чуть более устойчивым (он даёт компилятору больше информации), но различие это не принципиально.
Контекст и так доступен в замыкании. Передавать его параметром нужно, если контекст изменяется. В варианте "замыкание получает экземпляр CarRepository, работающий внутри транзакции" это не нужно.
Копия (новый экземпляр, не тип) Database реализует уже объявленный интерфейс CarRepository, именно его я предлагаю передавать в замыкание.
Возможно, для conn придется использовать интерфейс, подобный приведенному ниже в комментариях QueryExecutor.
Не удобнее ли вместо контекста (где зачеркнуто)
func (db *Database) WithinTransaction(ctx context.Context, tFunc func(
ctx context.Context) error) errorпередавать копию Database с транзакцией в поле
conn
?func (db *Database) WithinTransaction(ctx context.Context, tFunc func(db CarRepository) error) error
Метод model, функции injectTx, extractTx тогда, возможно, совсем не понадобятся.
Ух. Не трогаем специалистов. Они молодцы и вообще справились.
Если вы намекаете на 32-битный unixtime — во-первых снимаю шляпу, во-вторых вы совершенно правы — такого рода ошибки решаются крайне сложно даже оригинальными разработчиками.
Я резко прокомментировал вот эти строки цитируемые в статье:
Почему резко прокомментировал? Работая с чужим кодом часто чувствуешь дискомфорт. Как раз вот это ощущение "казалась непостижимой". Причем дискомфорт этот никак не связан с качеством программы, скорее с тем, что абстракции, терминология, подход непривычны.
Есть соблазн объявить: "Ничего понять нельзя, плохой код, давайте перепишем". Не решить проблему, а просто отложить её решение, сбежать в зону комфорта.
И навык (именно навык) преодоления этого дискомфорта, умения сначала разобраться с тем, что другой разработчик ХОТЕЛ сделать и уже потом с тем, как он это делал и что у него получилось, мне кажется одним из самых недооцененных.
Дальше по тексту (цитата из цитаты из статьи):
Я понимаю почему написано именно так. Но всё равно "разумеется, она должна была" и "никто не знал, что она будет" в одном абзаце звучат странно. Как описание непостижимого черного ящика внутри черного ящика непостижимости.
Ощущение, что за пару десятилетий не нашлось ни одного человека, который бы заглянул туда из простого любопытства.
Я думаю, что эта самая "непостижимость", эмоциональная реакция, часто является ключевым фактором, из-за которого программа либо преждевременно переписывается (часто неудачно) либо живет слишком долго. Непостижимость ведет к неадекватной оценке существующего решения. И я против того, чтобы маскировать неадекватность оценки (одновременно завышенные ожидания и негативный отзыв) концепцией технического долга или гниения.
Мы говорим о разных вещах. Есть естественная смерть продукта — та самая промышленная археология. Когда ПО не компилируется, когда инжектор оказывается дешевле карбюратора. Когда логичнее купить новый автомобиль, чем поддерживать старый.
А есть — запланированное устаревание. Которое потребителю обходится дороже в любом случае, а в случае ПО — еще и умножает риски на порядок. Потому что это не покупка новой модели автомобиля, а её разработка с нуля, причем людьми, до этого занимавшихся оросительными системами, расклейкой афиш и игрой на скрипке. Которые сходу вам скажут, что автомобиль — дерьмо, потому что "дворники" не дают нормального орошения, сигнал какой-то скучный, а номерной знак с таким шрифтом и подачей ни одного билета не продаст.
Ну как не согласиться насчёт баланса?
Я немного не согласен с "меньше усилий чем сделать переделать".
Тут такая штука — в статье кроме смены поколений ПО (мы как-то слишком сейчас на ней сконцентрировались), есть еще банальная некомпетентность. Не та, где "соискатель не продемонстрировал знание современных парадигм проектирования" а намного более важная — способность разобраться в проблеме. Вот смотрите:
Что видите? Хреновую старую программу? А я вижу, что автор не умеет и не хочет читать чужой код. Существует в узком пространстве привычных шаблонных решений.
И, что НАМНОГО хуже — не имеет чёткого представления о предметной области.
Человек не понимает какую проблему решает программа, поэтому не может и не хочет разобраться в том, как она это делает. Отсюда уверенно накидывает о гнили, протухлости и прочей ерунде.
В финансовой сфере основные затраты и риски при разработке новой версии связаны с обучением разработчиков. Они косячат и будут косячить. Особенно если концентрируются на технологии, а не проблеме. И можно десятилетиями вкладывать в
косякиобучение сотни тысяч в год, а можно использовать рабочее ПО до самой его естественной смерти и вложиться в косяки аврально, но один раз, для создания нового поколения. Тоже ведь баланс.В статье речь идет о плановом устаревании. С точки зрения производителя — отличная штука. Но покупатель с этим не всегда согласен.
В смысле "давайте победим старость отстрелами достигших 30 лет"?
А что будет если нужно просуммировать длину ответа трех ПОСЛЕДОВАТЕЛЬНЫХ запросов? Где, скажем, url второго получаем из ответа первого, а url третьего — из второго?
Для того, чтобы записать, скажем такую странную штуку:
придется использовать вложенность (которую чаще именуют callback hell'ом). Ну или вызовы
asyncio.run
в коде везде, где раньше случалось встретить await, превращая код в по-настоящему синхронный. И в любом случае — плохо читаемый.Можно тысячу раз спросить "а на..., простите, зачем?!" глядя на цикл с await выше, но никак не "а что, собственно, этот код делает?". Чего, боюсь, не скажешь о коде, написанном с помощью описанного в статье подхода.
Да пожалуйста! Вот только не молитесь на неё.
Вы заметили как понятие чистоты из количественной характеристики (символы на блок кода) мутировало в абстракцию, по восприятию близкую к божественной непогрешимости?
Меня вот совсем не пугает фетишист, тихонько получающий удовольствие от процесса кодирования. Они обычно продуктивны.
Кто меня по-настоящему пугает — так это идеалист, постоянно находящийся в глубокой фрустрации и несущий из этой фрустрации свет. Обычно методом выжигания неверных.
Сначала человек страдает от того, что не получается найти решение положенного градуса святости. Потом паникует от того, что в выстраданное, сияющее решение нужно вносить коррективы. Месяцами тупит потому что картинка в голове не складывается. Потом годами занимается чем угодно, только не тем, чем нужно. Просто потому, что сложившаяся красивая картинка совершенно не соответствует решаемой задаче.
Меня до чертиков пугает фокус на чистоте кода и архитектуре вместо понимания проблемы. Не получается разобраться сходу? Сделай и потом отрефактори. Лучше понимая что нужно сделать. Лучше понимая как. Обычно у человека, хорошо понимающего ЧТО он делает, код как-то сам собой получается сопровождаемым.
Но нет же, как можно, что за профанация и богохульство, придет же технический долг и мы все умрем. Давайте лучше сразу подстрахуемся: триста земных поклонов каждый день, строгий пост (только best practices, ничего скоромного) и будем говорить только на латыни: "Давайте имплементируем дизайн-паттерны релевантные контексту скоупа карентовой бизнес-стори". Теперь уж точно ничего не сможет пойти не так — святая архитектура услышит наши молитвы и нас защитит, да будет она чиста вовеки.
Код — утилитарная штука. Инструмент, а не объект поклонения. Можно слепить из него арт-объект. Можно посоревноваться, замерить какой код будет выше, дальше или там сильнее. Раздвинуть границы. Можно, простите, даже дрочить на него. Соблюдая правила гигиены и выдерживая график. Но, блин, пожалуйста, пожалуйста, не надо в него веровать.
Как-то так получается, что синхронный — дура, а асинхронный — молодец.
Пара (ок, чуть больше) замечаний:
В текущем варианте — overengineering в чистом виде.
Техническая часть статьи сводится к тому, как силами всего трех дополнительных модулей и нескольких подключенных библиотек в Django-приложение можно встроить декларативный язык для описания stories. И что это дает некоторые преимущества при отладке бизнес-логики.
Сама реализация, ограничения, которые она накладывает на оптимизацию, технические проблемы, которые придется решать, полностью аналогичны тем, что встречаются при реализации GraphQL-сервера.
Сейчас, судя по приведенному коду, возможные проблемы не решаются никак.
Более того — решить их на уровне библиотеки так, чтобы разработчик мог сконцентрироваться на бизнес-логике, в текущей, синхронной, версии Django не получится.
Комментарий относится к первым двум абзацам статьи, где анализируется дизайн кита.
В них автор статьи приходит к выводу что дизайн — ужасен, потому что кит — не рыба. А еще кит — не хищник и вообще легаси. И нужно все переписать.
При том, что пятиминутного изучения domain'а (предметной области) должно было бы, чтобы понять, что рыба размером с кита просто задохнется. А хищник такого размера — умрет голодной смертью.
Пара замечаний по неудачному дизайна кита.
Возможно, MVP акулы и выглядит перспективнее, но мне кажется, что с ростом проекта разработчикам пришлось внести коррективы в то, что поначалу казалось таким очевидным.
Иронично то, что автор, реализуя в библиотеке "новый и прорывной подход параллельных вычислений, качественно превосходящий реализацию, например, в Go", реализует в Python аналоги каналов и context.Context из Go.
Видимый плюс библиотеки — трейсбэки. Которые режутся стандартной библиотекой не без причины. Для получения трейсбека нужно держать в памяти стек, который корутиной (да больше никем) использоваться не будет.
Код из статьи, использующий стандартный asyncio, мне кажется понятнее и очевиднее кода, написанного с использованием Trio. Использование with вместо asyncio.wait совсем не понравилось. Но здесь дело вкуса.
Для завершения корутины библиотека может выбросить исключение внутри third-party library. Это совсем нехорошо.
В общем не совсем понятно зачем. Наверное, содержит электролиты.
Бенчмарки TechEmpower проводятся по семи сценариям. Есть и бенчмарк http сервера (plaintext). Он упоминается в статье, туда легче всего попасть. Фреймворки ссылаются именно на него. Там замеры делаются очень даже понятно чего
, причем самой длинной линейкой.Опишу ситуацию, в которой остальные, синтетические, бенчмарки полезны.
Скажем есть возможность, даже необходимость, сменить стек (фреймворк, язык программирования, всё, что душа пожелает). Собирать его по частям — ну очень утомительно. Вот 5 фреймворков, вот 3 клиента postgres, вот так (обещают) будет работать быстро, а вот так — идиоматичненько. А может использовать MySQL? Вот еще 2 клиента на выбор. И так по каждому пункту. И это если отбросить вообще неведомые вещи, которые хороший парень ну очень рекомендует.
Такая непрерывная фрустрация, когда информации много, тонешь. Рыться можно часами и сутками, а решение в итоге принимается с ощущением выбора наугад.
Синтетические бенчмарки дают готовый, подобранный другими людьми набор с четкими результатами (ну очень удобно, если есть требования по нагрузке). Помогает сузить стартовый набор вариантов, одновременно предлагая несколько работающих примеров использования.
А полигон для исследований так совсем отличный.
Да!
Вальяжное вступление, возможно, сбивает с толку. Мне НРАВИТСЯ actix, я в восторге от того, насколько уместны, точны и осмысленны те технические решения, которые я увидел в коде.
В бенчмарках actix нет чита. Есть условие проведения бенчмарка — запросы к БД должны выполняться последовательно. В тексте я процитировал код, который может человеком, привыкшим к работе с пулом соединений, восприниматься как параллельный. Это не так.