Search
Write a publication
Pull to refresh
4
0
Мартынов Максим @dolfinus

Швец, жнец, на Python'е игрец

Send message

коллекции макро‑тестов для языка программирования Python

Faster CPython вообще не про тесты, это про изменение внутренней работы интерпретатора, чтобы поднять его производительность

Всё выглядит так, что авторы собираются в какой-то момент собираются ввернуть официальную коммерческую поддержку

А можно ссылку на источник?

  1. alpine в качестве базового образа для Python проектов - довольно таки плохая идея.

  2. Используйте для прода multistage build - отдельный образ с установкой poetry+сборкой зависимостей+созданием venv, а в финальный образ добавляем только этот venv и код проекта. Сам poetry далеко не пушинка (он вместе с зависимостями весит 70-100Мб), а если какие-то из пакетов требуют компиляции из исходников, то gcc/autoconf/make и т.п. весят ещё больше.

  3. Зачем собирать образ дважды? Первый раз в CI ддобе, второй на хосте через docker compose up --build. Соберите образ один раз, положите в Dockerhub/Github registry, и на хосте выполняйте docker pull. Ну и для сборки в Github есть специальные actions, с кэшированием, multiarch и т.п., гораздо лучше сборки через docker compose.

  4. Можно не прописывать запуск ruff через pre-commit и на уровне CI разными командами. Например для Github есть pre-commit.ci

Нужно просто прикрутить dependabot/renovate/периодический poetry update к репозиторию. Обновлять зависимости без прогона тестов я бы уж точно не стал.

Вместо COPY poetry.lock он почему-то создаётся заново. Весь его смысл теряется

В Github Actions на каждый запуск джобы создаётся чистая виртуалка из шаблона, в которой прогоняются все необходимые команды, и после завершения она удаляется. Иначе любые изменения в пакетах, файловой системе и т.п. могли бы попасть в CI другого репозитория, и натворить там дел. В on-premise такого может и нет, не пользовался.

В CI runner Github Actions так можно. Иначе невозможно было бы устанавливать пакеты в ОС, например.

Очень не хватает технических деталей - примеров запросов, которые пришлось изменить, сравнение времени выполнения до и после, кода для функции хэширования (да хотя бы ее названия), что за "страшные недокументированные команды" пришлось запускать. Со всей этой информацией пост вполне мог стать кандидатом для добавления в закладки, и мог бы кому-нибудь пригодится в реальных задачах. А так пробежались по верхам, и все, "подписывайтесь на канал".

Ещё бы в сравнении указать размеры обоих индексов

Очень странная статья.

  • Сравнение производительности на запросах длительностью в несколько микросекунд, хотя на таких масштабах IO latency может нивелировать всю разницу промзводительности. На вряд ли кто-то из аналитиков и DS будет менять свой стек ради ускорения настолько коротких запросов. Тут нужно либо сравнивать больше данных, либо делать более сложные запросы, например join.

  • Не везде указано отличие в способе работы с данными. Pandas всегда работает с данными в памяти. Polars умеет и помещать данные в память, и работать в out-of-core режиме, обращаясь к файлам на диске и обрабатывая их небольшими чанками. DuckDB/Dask всегда используют out-of-core. Плюс многие либы сейчас используют под капотом Apache Arrow (в том числе Pandas 2.x), так что способ представления данных в памяти у них одинаковый, что позволяет легко передавать данные между ними без дополнительной конвертации.

  • Не указано различие в API - какие-то либы предлагают совместимый с pandas DataFrame API, у polars свой собственный DataFrame API (иммутабельный, в отличие от pandas) + есть поддержка SQL, у DuckDB только SQL.

  • Dask умеет в распределённый режим работы, когда воркеры могут запускаться на разных машинах, и обрабатывать отдельные кусочки данных, что даёт горизонтальное масштабирование. Pandas/Polars/DuckDB так не умеют, и их производительность ограничена ресурсами одного хоста. Dask имеет смысл сравнивать с Apache Spark, а не с ними.

  • Указаны последние версии либ, но не когда они были опубликованы. У Pydatatable последний коммит был год назад, выглядит не особо живым. Vaex как будто тоже остановился в развитии, релизов за последний год не было.

Есть и другие примеры компиляторов без зависимостей, которые предоставляются только в виде исходного кода

В мире C# это возможно и норма, с учётом того, что пользователи в конечном итоге скачивают программу в виде скомпилированного бинарника, и способ распространения исходного кода им не так важен. Но в питоне упаковка в бинарный файл это скорее исключение из правил - зачастую все распространяется в виде пакетов, и указывать в метаданных пакета зависимость на git репозиторий довольно неудобное решение.

добавить peco в наш репозиторий как подмодуль git, выполнив из корня нашего репозитория команду

Довольно странный способ установки. В Python обычно публикуют пакет на pypi.org, и тогда его можно установить любым пакетным менеджером.

Тем не менее, предполагается, что оно всё-таки где-то в стороне лежит. Не в service_1 , service_2 и service_3?

Описывать эту схему взаимодействия внутри каждого сервиса кодом или класть рядом .json/.yml - никакой разницы. Мы, например, экспортируем openapi.json в момент релиза, и прикладываем к остальным артефактам.

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

OpenAPI описывает, в какой endpoint клиент должен отправить запрос и в каком формате, а также какой ответ он получит. В AsyncAPI тоже самое - в какие топики/очереди клиент должен положить сообщения и в каком формате, а также в каком топике/очереди можно получить результаты (если они есть). Плюс какие требования у этого инстанса Kafka/RabbitMQ/etc по аутентификации. Что дальше будет по цепочке с этими данными, ни AsyncAPI, ни OpenAPI не описывают, - это бизнес-логика тех сервисов, которые из него получают результаты, а не его собственная.

Позволяет ли acyncAPI описывать динамический роуминг, где мы, например, по разным топикам и routingKey сообщение в зависимости от типа распихивать? Или routingKey вычисляемый описать?

Есть подстановки для переменных вроде {userId}, по аналогии с path параметрами в OpenAPI. Либо я не понял вопроса.

UPD: промахнулся, это был ответ на https://habr.com/ru/articles/860604/comments/#comment_27590436

Ну это как я понимаю в сторонке от кода лежит, может и разъехаться

Зависит от инструмента. К примеру, FastStream умеет генерировать AsyncAPI схему из аннотаций типов в коде.

А что даст такое хранение плана dataframe в Atlas? В реальных ETL процессах постоянно происходит какие-то изменения, план сложно назвать постоянным. Задача была в изучении того, как планы меняются во времени?

И как с производительностью?

COPY будет передавать данные через мастер, он для таких объёмов не предназначен. Нужен CREATE EXTERNAL TABLE на стороне Greenplum + веб-сервер на стороне Spark executor'ов, реализующий gpfdist протокол, чтобы передавать данные напрямую на GP сегменты, минуя мастер.

Чтобы "продать" это разработчикам, нужно описать более понятные для них преимущества:

  • Т.к. UUIDv7 значения монотонно возрастают (по крайней мене первые 48 бит), БД при построении статистики по таблице могут увидеть корреляцию со значениями других столбцов (с датами, со другими числовыми значениями), и генерировать более оптимальные планы выполнения запросов.

  • Из-за все тех же возрастающих значений B-tree индексы перестает раздувать, и вставка выполняется быстрее.

  • UUIDv7 можно будет использовать как primary key для партиционированной таблицы - ключом партиционирования можно сделать вшитый в него timestamp. При доступе к конкретной записи вместо фуллскана всех партиций будет выполняться поиск только в той, которой принадлежит этот timestamp. С UUIDv4 же нужно дополнительное поле с timestamp, которое придется явно добавлять во все фильтры, и в случае PRIMARY KEY добавляет головной боли.

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

Слияние дубликатов - дубликаты же не по одному id определяются, а по комбинации других полей. UUID тут ничего нового не даст, дубликаты вообще не обязательно прилетают в один и тот же промежуток времени, чтобы его внутренний timestamp тут чем-то помогл.

Сквозной поиск объекта по его UUID во всей базе/API - без вшитого в идентификатор типа записи это довольно проблематично реализовать, нужен кастомный генератор значений + функция для извлечения типа из id. Возможно проще использовать идентификаторы вида {type}:{uuid}, как это делают например в GraphQL Relay.

1
23 ...

Information

Rating
10,170-th
Location
Москва, Москва и Московская обл., Россия
Works in
Date of birth
Registered
Activity