Celery выполняются в отдельном потоке
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Celery: Выполнение в отдельном потоке
Это не совсем точное утверждение. Celery — это не просто выполнение кода в отдельном потоке. Это распределённая очередь задач (distributed task queue), которая выполняет задачи в отдельных процессах на отдельных машинах.
Чем Celery НЕ является
❌ Не threading (многопоточность)
import threading
# Это просто поток в одном процессе
def background_job():
print('Работаю в потоке')
thread = threading.Thread(target=background_job)
thread.start()
Проблемы:
- Все потоки в одном процессе
- Если одна задача упадёт — может упасть всё
- GIL (Global Interpreter Lock) снижает параллелизм
- Нельзя масштабировать на несколько машин
- При перезагрузке приложения потеряются невыполненные задачи
Что такое Celery
Архитектура
┌─────────────────────┐
│ Django приложение │ Отправляет
│ (Web Server) │ задачи
└──────────┬──────────┘
│
│ send_task()
│
┌──────────▼──────────┐
│ Message Broker │ RabbitMQ / Redis
│ (очередь задач) │ Хранит задачи
└──────────┬──────────┘
│
┌────┴────┬──────────┐
│ │ │
┌───▼──┐ ┌───▼──┐ ┌───▼──┐
│Worker│ │Worker│ │Worker│ Выполняют
│ #1 │ │ #2 │ │ #3 │ задачи
└──────┘ └──────┘ └──────┘
Process Process Process
Суть Celery
- Асинхронность — приложение отправляет задачу в очередь и сразу возвращает ответ
- Распределённость —워커ы могут быть на разных серверах
- Надёжность — задачи сохраняются в broker'е до выполнения
- Масштабируемость — добавляйте워커ов по мере необходимости
Пример: Отправка Email
Проблема: синхронное выполнение
from django.views.decorators.http import require_http_methods
from django.core.mail import send_mail
@require_http_methods(["POST"])
def register_user(request):
user_email = request.POST.get('email')
# Синхронная отправка email
send_mail(
'Добро пожаловать!',
'Спасибо за регистрацию...',
'noreply@example.com',
[user_email],
fail_silently=False,
)
# Отправка занимает 2-5 секунд
# Пользователь ждёт ответа
return HttpResponse('Зарегистрированы!')
Проблема: пользователь ждёт 5 секунд, пока письмо отправится.
Решение: асинхронное с Celery
# tasks.py
from celery import shared_task
from django.core.mail import send_mail
@shared_task
def send_welcome_email(user_email):
"""Задача для отправки письма"""
send_mail(
'Добро пожаловать!',
'Спасибо за регистрацию...',
'noreply@example.com',
[user_email],
fail_silently=False,
)
return f'Email sent to {user_email}'
# views.py
from django.http import HttpResponse
from .tasks import send_welcome_email
def register_user(request):
user_email = request.POST.get('email')
# Отправляем задачу в очередь
send_welcome_email.delay(user_email)
# Возвращаем ответ сразу! (~10ms)
return HttpResponse('Зарегистрированы!')
Механика:
send_welcome_email.delay(email)отправляет задачу в Redis/RabbitMQ- Функция возвращает async result ID и сразу выходит
- На отдельном сервере worker получает задачу из очереди
- Worker выполняет
send_welcome_email(email)в отдельном процессе - Результат сохраняется
Celery vs Threading
Threading
import threading
import time
def send_email_thread(email):
time.sleep(3) # Отправка
print(f'Отправили {email}')
# В Django view
thread = threading.Thread(target=send_email_thread, args=(user_email,))
thread.start()
Проблемы:
[PID 1000] Django процесс
├─ Main thread (Web запросы)
├─ Thread 1 (send_email) <- может упасть
├─ Thread 2 (send_email) <- может упасть
└─ Thread 3 (send_email) <- может упасть
Если процесс 1000 упадёт — все потоки тоже упадут!
Все задачи потеряются!
Celery
[PID 1000] Django процесс
└─ send_task() -> Redis
[PID 2000] Worker процесс #1 <- выполняет задачи
[PID 2001] Worker процесс #2 <- выполняет задачи
[PID 2002] Worker процесс #3 <- выполняет задачи
Если Worker #1 упадёт — остальные продолжат.
Если Django упадёт — задачи останутся в Redis и выполнятся позже.
Типы выполнения Celery
1. Асинхронное (самое частое)
@shared_task
def long_running_task(param):
# Выполняется где-то на worker'е
return result
# В view - не ждём результата
long_running_task.delay(param)
return 'Задача принята'
2. С ожиданием результата (синхронное поведение)
# Ждём результат (timeout 10 секунд)
result = long_running_task.delay(param)
try:
output = result.get(timeout=10) # Блокирует поток
except TimeLimitExceeded:
print('Задача не завершилась за 10 сек')
3. Scheduled (периодические задачи)
from celery.schedules import crontab
app.conf.beat_schedule = {
'every-10-seconds': {
'task': 'tasks.cleanup_old_sessions',
'schedule': 10.0,
},
'every-morning-at-8am': {
'task': 'tasks.send_daily_digest',
'schedule': crontab(hour=8, minute=0),
},
}
Когда использовать Celery
✅ Отправка email и SMS ✅ Обработка больших файлов ✅ Интеграция с внешними API (могут быть медленные) ✅ Периодические задачи (очистка БД, синхронизация) ✅ Обработка изображений, видео ✅ Сложные вычисления ✅ Когда нужна отказоустойчивость
❌ Очень быстрые операции (< 100ms) ❌ Простые веб-приложения без background job'ов ❌ Если нет надёжного message broker'а
Выводы
- Celery НЕ выполняется в отдельном потоке — это отдельный процесс
- Celery это распределённая система —워커ы могут быть на разных машинах
- Celery это очередь задач — tasks хранятся в broker'е до выполнения
- Celery обеспечивает надёжность — если worker упадёт, задача переведётся другому
- Celery масштабируется — добавляйте worker'ов горизонтально
Этот подход позволяет создавать responsive веб-приложения, которые не блокируют пользователей на долгих операциях.