Django异步处理

8
我有一堆Django请求,执行一些数学计算(用C编写并通过Cython模块执行),可能需要不确定的时间(大约1秒)来执行。此外,这些请求不需要访问数据库,并且彼此独立于Django。
现在,所有内容都是同步的(使用带有“sync”工作程序类型的Gunicorn),但我想使其异步和非阻塞。简而言之,我想做以下几件事:
1.接收AJAX请求 2.将任务分配给可用工作程序(而不会阻塞主Django Web应用程序) 3.工作者以某个未知的时间执行任务 4.Django在任务完成时将计算结果(字符串列表)作为JSON返回
我非常新手异步Django,所以我的问题是什么是最好的堆栈来实现这一点。这种流程是否适合任务队列?是否有人推荐Tornado + Celery + RabbitMQ或其他东西?
提前谢谢!

你如何处理计算结果? - Sam Dolan
将结果(以JSON格式)返回给用户的浏览器。 - Stephen Diehl
2个回答

14

这个情况下使用Celery非常适合。

由于你所做的事情相对简单(即:你不需要关于任务路由的复杂规则),你可以使用Redis作为后端,这意味着你不需要设置/配置RabbitMQ(在我的经验中,这更加困难)。

我使用最新版的Celery作为开发构建,并且这是相关配置的要点:

# 以Redis作为队列
BROKER_BACKEND = "kombu.transport.pyredis.Transport"
BROKER_HOST = "localhost"
BROKER_PORT = 6379
BROKER_VHOST = "0"
# 在Redis中存储结果 CELERY_RESULT_BACKEND = "redis" REDIS_HOST = "localhost" REDIS_PORT = 6379 REDIS_DB = "0"

我还使用了django-celery,这使得与Django的整合变得更加顺畅。

如果需要更多具体的建议,请评论区留言。


1
此外,我使用 gevent 和 monkey patching 与 Celery 没有任何问题,因此如果您使用 gevent gunicorn worker 并 monkeypatch celery,一切都应该是神奇的异步。 - David Wolever
谢谢你的建议。我以前尝试过使用gevent工作进程和猴子补丁,但它会使我的应用程序变得非常缓慢。我怀疑这是由于我与MySQL的阻塞连接引起的。我需要转移到另一个数据库吗? - Stephen Diehl
抱歉,我没有使用过 gevent 和其他数据库,所以我无法回答。也许你可以发另一个问题来询问这个呢? - David Wolever
3
MySQLdb驱动程序是用C语言编写的,不使用Python套接字模块。这意味着它无法进行monkey patching,并且会阻塞整个gevent循环。https://github.com/mthurlin/gevent-MySQL 是一个异步版本。 - Alex Recarey
我是Celery的忠实粉丝,经常用它来处理长时间运行的任务,而无需等待结果。对于OP的使用情况,似乎异步等待Celery工作进程完成任务,以便我们可以响应AJAX请求仍会阻塞Django Web应用程序,对吗? - mateolargo
1
是的,如果调用类似于 my_task.apply(…) 的方法,Django 线程将会阻塞等待任务完成。如果任务需要大量的 CPU 计算,这可能是有意义的... 但它并不会释放 Django 线程。 - David Wolever

0

由于您计划使其异步(可能使用类似gevent的东西),因此您还可以考虑为计算工作创建一个线程化/分叉后端Web服务。

异步前端服务器可以处理所有轻量级工作,从适用于异步的数据库(如redis或具有特殊驱动程序的mysql)获取数据等。当需要进行计算时,前端服务器可以将所有输入数据发布到后端服务器,并在后端服务器完成计算时检索结果。

由于前端服务器是异步的,因此在等待结果时不会阻塞。与使用celery相比的优点是,一旦结果可用,就可以将结果立即返回给客户端。

client browser <> async frontend server <> backend server for computations

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接