Как асинхронно запускать задачи обработки данных в быстром API?

У меня есть маршрут в моем быстром приложении API (пример кода ниже). мой корневой маршрут вызывает асинхронную функцию read_root. в этой функции я хочу запросить базу данных, получить некоторый результат и загрузить его в aws в корзину s3. Мне не обязательно ждать завершения операций с базой данных, поскольку обработка данных и их загрузка в s3 может занять некоторое время. Я создал еще одну асинхронную функцию под названием call_database, выполняющую вызов базы данных, обработку и, наконец, загрузку файлов в s3, но вся эта операция является синхронной, т. е. вызов базы данных, получение результатов из базы данных и обработка данных, а затем загрузка в s3.

мой вопрос: может ли функция быть определена как асинхронный процесс таких синхронных операций? и пока они находятся в процессе, можно ли в моем случае вернуть ответ («привет»: «мир») на http-вызов. это завершит этот http-запрос/ответ. но я предполагаю, что функция call_database будет работать до тех пор, пока файлы не будут загружены в s3?

это правильное понимание и реализация?

from typing import Union

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def read_root():
    await call_database()

    return {"Hello": "World"}


async def call_database():
   //syncrohonous call to database
   //get the result back , and upload it to aws s3

Поведение await в Python блокирует выполнение сопрограммы (в данном случае функции read_root) до тех пор, пока ожидаемое не завершится (функция call_database). На практике это означает, что ваш текущий код не вернет ответ {"Hello": "World"} до тех пор, пока операция с базой данных не будет завершена.

amoralesc 16.07.2024 21:59

Чтобы заменить выполнение этих операций (вызов базы данных, загрузка s3), вы, вероятно, захотите использовать очереди задач. FastAPI включает поддержку фоновых задач . Другой рекомендуемый подход — использование Celery, проверенной библиотеки для использования очередей задач в Python.

amoralesc 16.07.2024 22:00

Связанные вопросы по StackOverflow: асинхронное/ожидающее поведение , фоновые задачи FastAPI

amoralesc 16.07.2024 22:02

@amoralesc — спасибо за ваши идеи. Я пройду по ссылке, которую вы предоставили. концептуально я понимаю, что ключевое слово await будет ждать, пока задача не будет завершена, а затем продолжит остальную часть программы. Итак, есть ли лучший пример, когда нам следует использовать конструкцию async/await?

kishi 16.07.2024 22:37

Конструкции async/await и модуль asyncio в целом лучше всего использовать, когда ваша программа привязана к вводу-выводу, и я думаю, что улучшение производительности более очевидно, когда одновременно выполняется несколько операций ввода-вывода. Обращение к базе данных — это именно операция ввода-вывода (как и загрузка файла в S3, если уж на то пошло). Поскольку вы используете FastAPI, я также предполагаю, что вы используете сервер ASGI, такой как uvicorn + построитель ORM/запросов, который поддерживает асинхронность. В этом сценарии вполне допустимо определить вызовы базы данных как асинхронные функции.

amoralesc 16.07.2024 23:20

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

amoralesc 16.07.2024 23:26

Теперь очень медленные операции (под медленными я подразумеваю >10 секунд), результат которых обычно не ожидается немедленно сообщить клиенту (например, загрузка больших файлов в S3), лучше всего подходят для фонового исполнителя. Именно здесь на помощь приходят фоновые задачи FastAPI или задачи Celery. Затем вы можете выбрать, как сообщить о результате этих операций вашему клиенту, в зависимости от вашего варианта использования: простое обновление базы данных, электронная почта, веб-перехватчик и т. д. Другим примером фоновых задач являются запланированные единицы работы, которые вам необходимо запускать каждый интервал x. времени, например очистка файлов на сервере каждый день в полночь.

amoralesc 16.07.2024 23:34

В дополнение к ссылкам, представленным на баннере выше, обратите внимание на этот ответ и этот ответ.

Chris 17.07.2024 10:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
8
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Думаю, вы ищете фоновое задание

from typing import Union

from fastapi import FastAPI, BackgroundTasks

app = FastAPI()

def upload_to_s3(data: dict):
    # your upload process here

@app.get("/")
async def read_root(background_tasks: BackgroundTasks):
    data_to_upload = await call_database()
    background_tasks.add_task(upload_to_s3, data_to_upload)
    return {"Hello": "World"}


async def call_database():
   //syncrohonous call to database
   

Вам не хватает декларации для background_tasks.

AKX 16.07.2024 22:04

Другие вопросы по теме