Иван Зайцев @IvanZaycev0717
Fullstack Developer, Москва
Information
- Rating
- Does not participate
- Location
- Москва и Московская обл., Россия
- Registered
- Activity
Specialization
Fullstack Developer
Python
Fastapi
JavaScript
Vue.js
SQL
MongoDB
Fullstack Developer, Москва
Открытие сайта в сентябре, сейчас идет наполнение контентом. Пока заглушка на сервере стоит. Когда контентом будет заполнен, сайт откроется.
Кстати хорошо, что сказали. Я уже уточнил на заглушке, что происходит и когда открытие сайта.
В публичном репозитории все работает для запуска с локальной машине, но у сайта на сервере будет больше фич
Публичный ключ указываем в глобальных настройках GitHub, чтобы можно было клонировать репозиторий. А приватный ключ указываем в Secrets репозитория нашего проекта, чтобы можно было реализовать CI/CD через GitHub Actions.
Есть супер объяснение как эти ключи получать и что куда класть - https://www.youtube.com/watch?v=V2YYhGn3MGo&ab_channel=Chaby%27sTech
У нас приватный ключ будет использован в CI/CD
Конкретно в этом случае я использовал Flask, потому что, исходя из технического задания, более логичной архитектурой приложения будет монолит MPA. А такая архитектура отлично реализуется на Flask.
Вы абсолютно правильно заметили, что FastAPI хорош для микросервисной архитектуры с реализацией приложения в виде SPA. У меня сейчас в работе проект, где именно микросервисная архитектура и там я использую FastAPI
А почему бы нам не автоматизировать использование данной формулы для автоопределения количества дотсупных логических ядер на виртуальной машине. Например, с помощью такого скрипта gunicorn.conf.py
Ну а дальше все очень просто:
Хорошо, что вы попробовали и не побоялись выложить, учитывая какие софт-скиллы у многих комментаторов на Хабре. Можно сделать лучше. Приведу примеры для синхронной и асинхронной алхимии, как сделать лучше
ПОРАБОТАЕМ В СИНХРОННОЙ АЛХИМИИ
В обычной синхронной алхимии используется, как правило, либо execute для выполнения произвольных SQL-запросов и возвращает объект
ResultProxy
, либо scalars для выполнения запросов, которые возвращают ровно один столбец и одну строку, и возвращает значение этой единственной ячейки напрямую. То есть если бы это была обычная синхронная сессия, такой синтаксис был бы далеко не самым лучшим решиением.Код для синхронной алхимии:
У scalars не нужно писать all() - оно по умолчанию установлено
ТЕПЕРЬ ПОГОВОРИМ ОБ АСИНХРОННОЙ АЛХИМИИ
Как верно было замечено выше надо создать отдельную асинхронную сессию. У движка дожен быть асинхронный драйвер, например, asyncpg для PostgreSQL
Метод session.stream_scalars(query) обеспечивают возврат асинхронной версии объекта, который поддерживает протокол асинхронной итерации Python.То есть для его итерации вы будете использовать не простой цикл
for
, а асинхронныйasync for
. Он позволяет выполнять асинхронные операции в процессе итерации. Итерации выполняются в асинхронном контексте, что позволяет эффективно использовать время CPU при ожидании завершения асинхронных операций вместо блокировки процесса.И на последок небольшую психологическую поддержку Вам хочу оказать: продолжайте дальше писать статьи, вы работаете с довольно сложными вещами. И официальный туториал по SQLAlchemy написан, слабо говоря, не лучшим образом. Книга только одна вменяемая по этой теме - вот эта. Ну а к хамству и грубости надо просто привыкнуть - как сказал не последний человек в мире Python Никита Соболев, что в России все отлично с хардами, но все ужасно с софтами. Грубость в комментариях к вам никакого отношения не имеет, этих людей так с детсва воспитало наше общество
Эта инструкция работать не будет работать для IP-адресов из России, так как docker.elastic.co заблокировало доступ для "дорогих россиян".
Но выйти из положения можно - здесь я использовал рамдомную версию Elasticsearch
Подтягиваем образ с DockerHub
Далее создаем контейнер
В Docker Compose в YAML-файле это будет выглядеть так:
Вообще очень хорошие статьи - всегда хочется немного освежить основы. Причем оригинальный автор Miguel Grinberg - довольно известный ирландский программист. Если встретите его книжку по SQLAlchemy 2.0 - советую ознакомиться, очень хорошо она написана
Приведу небольшой пример из современного GameDev: крупная корпорация Ubisoft сожрала многие студии и что мы видим - полную деградацию и чистый убыток в полмиллиарда евро. Крупные корпорации типа Microsoft выпустили на свет абсолютно провальный Redfall, после чего закрыли студию Arkane. Также другой крупный тайтл Starfield имеет "в основном отрицательные" недавние отзывы в Steam.
В условиях рыночной экономики всегда будут оставаться небольшие независимые студии, чьи продукты будут покупать. И эти студии будут выпускать качественные продукты в отличии от корпораций.
Немного подушню, но на диаграммах неплохо было бы проценты ставить.
Похоже вы не поняли для чего я это сделал: вы не заметили, что при выполнении запросов плавно меняется progress bar. При нажатии кнопки "Начать" мы будем с помощью aiohttp отправлять запросы с максимальной скоростью. Пока картинки скачиваются, мы можем отправлять команды обновления progress bar хода выполнения из цикла событий asyncio в цикл событий Tkinter.
Очень интересно посмотреть как вы сделаете отзывчивый UI через пул процессов?
Это вы вырвали из контекста статьи. Это было написано ДО того, как я заговорил о многопоточности. Т.е. если реализовать длительную блокирующую операцию в mainloop(), то программа "застынет" и ОС подумает, что она зависла. Если реализовать длительную блокирующую операцию в дополнительнм потоке - то он застынет на время выполнения операции, а главный поток будет нормально работать. Вы даже статью нормально прочитать не смогли, вам главное кое-что на вентилятор побыстрее накинуть
Вы на Pull request такие же комментарии оставляете: "Зачем ты изобретаешь велоспед", "Хватит говнокодить"?
Знаете есть одна хорошая книга у Роберта Саттона пр то, с кем не надо работать. Судя по вашему тону вы мне именно таким и представляетесь.
Спасибо за комментарий. Я привел только один из способов реализации. Другой способ - в самом первом комментарии
В tkinter имеется собственный цикл событий mainloop(), который блокирует главный поток. Это означает, что любая длительная операция может привести к заморозке пользовательского интерфейса.
Избежать проблемы можно через выполнение функций, которые не блокируют этот цикл событий. Это достигается тем, что исполнение цикла событий в asyncio надо делать в отдельном потоке.
Про глобальную блокировку интерпритатора GIL на Хабре написан не один десяток статей.
А в чем чушь полнейшая, если по вашим словам "разницы в скорости по сравнению с asyncio никакой не будет"? Это просто 2 разных подхода для решения одной и той же задачи
Здесь больше эмоций, чем аргументированной критики. В моём заявлении нет ничего, что противоречило бы правильной реализации поставленной задачи
Конкретно для этого примера можно так сделать. Но представте, что у нас на сайт не предоставляет API. Я описал универсальный подход.
Все мы иногда любители этого. По поводу говнокода, я процитирую одного своего товарища, который толи в шутку, толи в заправду говорил: "Говнокод очень сильно ускоряет коммерческую разработку".
Я написал это приложение в своё удовольствие, никакой коммерческой составляющей здесь и в помине нет. Здесь просто показано одно из множества решений данной проблемы. Эффективное оно или нет - вы решаете сами для себя.
А теперь от меня вопрос:
Интерестно, у вас на работе такая же корпоративная культура? Тогда я вам сочувствую
Вот реальный пример генерации таких строк из QtDesigner с русским языком
А я бы стал
Ввёл команду так, как автор написал в статье. Где вы взяли такие цифры?
У PySide6/PyQt6 есть один интересный момент - размер скачиваемых с помощью pip - билиотек - 100Мб+. А представьте, что придется все это компилировать в exe. А нужен ли такой графический интерфейс, если я, например, использую пару радио-кнопок и одно поле ввода?
Я считаю, что Qt следует использовать только в том случае, когда нет подобного функционала в стандартной библиотеке Python - tkinter.
Генерация кода QtDesigner - это что-то с чем-то, если у вас русский язык в приложении. В сгенерированном py-файле присутсвует такая красота как u-строки, которую редко встретишь. Поэтому Qt в Python просто побаловаться можно, но не более того
без полного кода программы, конечно, сложно. Дело в том, что библиотека requests является блокирующей и используя эту библиотеку мы ничего не выигрываем. Я опять же не знаю исходного кода, но попробую воспроизвести и замерить скорости выполнения на основе того, кода, что вы воложили с моими догадками
Давайте запустим и посмотрим на результаты
Синхронный код работает чуть быстрее, чем асинхронный.
Таким образом, get_acces_token можко сделать обычной функцией, а в access_token убрать await. Корутина, где есть access_token в любом случае будет блокироваться из-за requests
В этой корутине отсутсвует оператор await, она будет работать синхронно, и не будет использовать основные преимущества асинхронности.
Что касаетяется статьи, задумка отличнейшая. Лет 5 назад такого джуна как вы с руками и ногами взяли бы. Да, увы курсы сломали рынок IT. Но рынок - это динамическая структура, поэтому, видимо, классические отклики - это утаревшая стратегия. Но какая-же новая?
Хочу отбросить ваши сомнения - приложение работает так, как задумывалось и правильно. Я решил выполнить чистый код приложения, убрав графический интерфейс, многопоточность, асинхронку. Вместо этого будет синхронный код и чистый пул процессов с функцией map. Результаты идентичны, что и в приложении. Можете сами проверить
У меня результаты такие
отличный комментарий. Спасибо, что сказали про Thread._daemonic - здесь моя невнимательность. Что касается применения модуля asyncio: использовал для реализации asyncio.gather чтобы дождаться завершения всех вызовов в списке call_coros
Я проверил, заменив list comprehension в алгоритме быстрой сортировки на создание обычных списков с append'ами и сравнил - результаты практически одинаковые. Ну если уж такое замечание пришло, я поменяю на классическую реализацию, чтобы ни у кого никаких сомнений не оставалось