Асинхронные функции в программировании обеспечивают эффективное управление ресурсами путем передачи управления контекстом выполнения. Во время выполнения длительных операций, таких как сетевые запросы или операции ввода/вывода с файлами, управление контекстом передается другим функциям или основному потоку выполнения. Это позволяет избежать блокировок, которые возникают в синхронном коде из-за ожидания завершения операций, так как в асинхронном подходе другой код может выполняться во время ожидания завершения операции.
Вот несколько преимуществ асинхронного кода в FastAPI
Асинхронность может быть полезной для улучшения производительности в приложениях, особенно когда задача требует ожидания на завершение операций ввода-вывода (I/O-bound), взаимодействие с базой данных или внешними API. Однако, для CPU-bound задач, где выполнение операций требует значительных вычислительных ресурсов, асинхронный подход менее эффективен из-за дополнительной сложности и накладных расходов на управление асинхронным кодом. В таких случаях, использование параллелизма или многозадачности может быть более подходящим решением для улучшения.
асинхронный код
Предположим, мы выполняем вычисление произведения двух огромных матриц. Такие операции являются CPU-bound, потому что они требуют значительных вычислительных ресурсов и выполняются на процессоре. В данном случае, использование асинхронного кода не даст преимущества, так как нет возможности передать управление другим задачам, пока текущая задача не завершится. Вместо этого, для ускорения вычислений, можно использовать параллельные потоки или процессы, чтобы распределить нагрузку на несколько ядер процессора.
В Python, например, можно использовать модуль multiprocessing
для создания процессов, которые могут выполняться параллельно и обрабатывать различные части матричного произведения одновременно. Это позволит более эффективно использовать вычислительные ресурсы и сократить общее время вычислений. Однако, стоит отметить, что в Python из-за существования GIL (Global Interpreter Lock), многопоточность не всегда может дать преимущества в производительности для CPU-bound задач. В таких случаях, использование процессов может быть более эффективным решением.
Для конкретного анализа производительности приложения рекомендуется провести тестирование и измерение производительности как асинхронной, так и неасинхронной версий приложения в контролируемых условиях. Это позволит определить, какой подход лучше соответствует требованиям вашего приложения.
Ниже представлен пример сервиса, который позволит оценить скорость работы в случае множества запросов.
from fastapi import FastAPI
from pydantic import BaseModel
import time
import asyncio
app = FastAPI()
class Item(BaseModel):
item_id: int
def predict(input_data):
time.sleep(1) # Имитация работы модели
return {"prediction": "класс A"}
async def predict_async(input_data):
await asyncio.sleep(1) # Имитация работы модели
return {"prediction": "класс A"}
@app.post("/predict/")
def predict_endpoint(item_id: Item):
result = predict(item_id.item_id)
return result
@app.post("/predict_async/")
async def predict_endpoint_async(item_id: Item):
result = await predict_async(item_id.item_id)
return result
Для корректного моделирования работы большого числа пользователей необходимо реализовать параллельные запросы к эндпоинтам. Однако для полноценного нагрузочного тестирования важно проводить тесты длительное время и использовать специализированные инструменты, такие как k6, Locust, Gatling, Hammer, Bombardier и другие. Эти инструменты позволяют более точно имитировать поведение пользователей и анализировать производительность системы под нагрузкой.
Такой подход позволяет получить достоверные данные о производительности системы, выявить узкие места и обеспечить стабильную работу в условиях высокой нагрузки.
Тип сервиса | Количество воркеров | Количество запросов | Процент ошибок | Среднее время ответа (мс) | Минимальное время ответа (мс) | Максимальное время ответа (мс) | Медианное время ответа (мс) | Запросов в секунду | Ошибок в секунду |
---|---|---|---|---|---|---|---|---|---|
Синхронный | 1 | 2343 | 0.00% | 2493 | 1122 | 3147 | 2200 | 39.27 | 0.00 |
Асинхронный | 1 | 5822 | 0.00% | 1014 | 1002 | 1184 | 1002 | 97.55 | 0.00 |
Синхронный | 4 | 5811 | 0.00% | 1018 | 1002 | 1188 | 1002 | 97.31 | 0.00 |
Асинхронный | 4 | 5812 | 0.00% | 1016 | 1002 | 1169 | 1002 | 97.32 | 0.00 |