← Назад к вопросам

Почему не рекомендуют использовать wsgiref в Python?

2.0 Middle🔥 201 комментариев
#FastAPI и Flask

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Почему не рекомендуют использовать wsgiref

Введение

wsgiref — это встроенный в Python модуль, предоставляющий простой WSGI сервер (WSGIServer). Хотя это выглядит удобно, его НЕ рекомендуют использовать в production, и даже для разработки есть лучшие альтернативы.

Основные проблемы wsgiref

1. Однопоточность (Single-threaded)

wsgiref обрабатывает запросы последовательно, один за другим:

# wsgiref
from wsgiref.simple_server import make_server

def app(environ, start_response):
    print("Начало обработки запроса")
    import time
    time.sleep(5)  # Имитация долгой операции
    print("Запрос обработан")
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [b'Hello']

# Если два клиента подключатся одновременно:
# Клиент 1: начало (0s) → конец (5s)
# Клиент 2: начало (5s) → конец (10s)
# Второй клиент ждёт 5 секунд, пока первый завершится!

server = make_server('localhost', 8000, app)
server.serve_forever()

Сравни с Gunicorn или другим production сервером:

# Gunicorn (многопроцессный)
# Запускается с 4+ workers'ами по умолчанию
# Клиент 1: обработка на worker 1 (0-5s)
# Клиент 2: обработка на worker 2 (0-5s) одновременно
# Оба завершаются за 5 секунд!

2. Проблема с блокированием

Если приложение делает I/O операции, весь сервер блокируется:

import requests
from wsgiref.simple_server import make_server

def app(environ, start_response):
    # Долгий HTTP запрос к внешнему API
    response = requests.get('https://api.example.com/data', timeout=30)
    
    start_response('200 OK', [('Content-Type', 'application/json')])
    return [response.content]

# Во время requests.get() сервер не может обрабатывать другие запросы!
# Все остальные клиенты ждут 30 секунд

server = make_server('localhost', 8000, app)
server.serve_forever()

С production сервером это не проблема:

# Gunicorn с 4 workers'ами может обрабатывать 4+ таких запроса одновременно
# Каждый worker блокируется независимо

3. Отсутствие масштабируемости

wsgiref не может масштабироваться:

# wsgiref
# Максимум 1 запрос в секунду (если каждый обрабатывается 1 сек)
server = make_server('localhost', 8000, app)
server.serve_forever()

# Gunicorn с workers
# При 10 workers'ах: 10 запросов в секунду параллельно
guniciorn --workers 10 app:application

4. Отсутствие переиспользования соединений

wsgiref не поддерживает connection pooling:

from wsgiref.simple_server import make_server

def app(environ, start_response):
    # Каждый раз создаётся новое соединение к БД
    import psycopg2
    conn = psycopg2.connect("dbname=test")  # Дорого!
    cursor = conn.cursor()
    # ...
    conn.close()

Производственные сервера используют pooling:

from psycopg2 import pool

db_pool = pool.SimpleConnectionPool(
    1, 20,  # Min и max connections
    "dbname=test"
)

def app(environ, start_response):
    # Переиспользует существующие соединения
    conn = db_pool.getconn()
    # ...
    db_pool.putconn(conn)

5. Отсутствие обработки ошибок и мониторинга

wsgiref не предоставляет:

  • Логирование ошибок
  • Мониторинг метрик
  • Graceful shutdown
  • Health checks
  • Process management
# wsgiref просто упадёт при необработанном исключении
from wsgiref.simple_server import make_server

def app(environ, start_response):
    raise ValueError("Критическая ошибка!")  # Сервер рухнул?

server = make_server('localhost', 8000, app)
server.serve_forever()  # Просто упадёт

6. Отсутствие безопасности

wsgiref имеет потенциальные уязвимости:

  • Нет HTTPS/SSL поддержки
  • Нет rate limiting
  • Нет защиты от DDoS
  • Использует небезопасные заголовки по умолчанию
# wsgiref не может работать с HTTPS
from wsgiref.simple_server import make_server
server = make_server('localhost', 443, app)  # Не поддерживается

# Gunicorn:
gunicorn --certfile=cert.pem --keyfile=key.pem app:application

7. Отсутствие hot reload

wsgiref требует ручной перезагрузки при изменении кода.

# Production сервера поддерживают graceful reload
gunicorn --workers 4 --reload app:application

Проблемы в development тоже

Даже для разработки wsgiref не идеален:

from wsgiref.simple_server import make_server

# Проблемы:
# 1. Нет автоперезагрузки при изменении файлов
# 2. Сложный debug при ошибках
# 3. Медленно при работе с несколькими потоками (он их не поддерживает)
# 4. Нет развитого вывода информации о запросах

server = make_server('localhost', 8000, app)
server.serve_forever()

Рекомендуемые альтернативы

1. Для разработки: Django/Flask встроенный сервер

# Django
python manage.py runserver
# Автоперезагрузка, полноценный debug, лучше обработка ошибок

# Flask
from flask import Flask
app = Flask(__name__)

if __name__ == '__main__':
    app.run(debug=True, reload=True)
    # Автоперезагрузка, интерактивный debugger

2. Для production: Gunicorn

# Установка
pip install gunicorn

# Запуск с 4 workers'ами
gunicorn --workers 4 --threads 2 app:application

# С timeout'ом и graceful shutdown
gunicorn --workers 4 --timeout 30 --graceful-timeout 30 app:application

3. Для production: uWSGI

pip install uwsgi

# Запуск
uwsgi --http :8000 --wsgi-file app.py --callable app

4. Для асинхронных приложений: Uvicorn

pip install uvicorn

# Запуск (для ASGI приложений, FastAPI и т.п.)
uvicorn app:app --workers 4

5. Для разработки FastAPI/Starlette

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
async def read_root():
    return {"Hello": "World"}

if __name__ == "__main__":
    # Встроенный сервер с автоперезагрузкой
    uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)

Сравнительная таблица

СерверПотокиProductionРазработкаСкоростьМонитор
wsgirefНетМедленно
Django runserverДаНорм
Flask devНетНорм
GunicornДаОтлично
uWSGIДаОтлично
UvicornДаОтлично

Когда wsgiref вообще используется?

Редкие cases:

  1. Образовательные цели —学 как устроен WSGI
  2. Микросервисы в контролируемых условиях — на закрытой сети, 1 запрос в минуту
  3. Хобби проекты для друзей — когда нет требований к надёжности
  4. Unit тесты — имитация WSGI сервера в тестах

Практический пример: почему wsgiref плохо

from wsgiref.simple_server import make_server
import requests
import time

def app(environ, start_response):
    # Запрос к внешнему API
    start = time.time()
    response = requests.get('https://httpbin.org/delay/2', timeout=10)
    elapsed = time.time() - start
    
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [f'Waited {elapsed:.2f}s'.encode()]

server = make_server('localhost', 8000, app)
print("Сервер запущен на http://localhost:8000")

# Если открыть 5 браузеров одновременно:
# wsgiref: 5 * 2 сек = 10 сек (последовательно)
# Gunicorn (4 workers): 2 сек (параллельно на разных workers'ах)

server.serve_forever()

Выводы

wsgiref НЕ рекомендуют:

  • В production — отсутствие масштабируемости
  • Для разработки — плохой debug, нет автоперезагрузки
  • Для I/O операций — однопоточность блокирует сервер
  • В критичных системах — отсутствие мониторинга

Используй вместо wsgiref:

  • Разработка: Django/Flask встроенный сервер или Uvicorn
  • Production: Gunicorn, uWSGI или Uvicorn
  • Асинхронные приложения: Uvicorn/Hypercorn
  • Обучение WSGI: разберись с кодом wsgiref, но не развёртывай его