Python中Django默认支持并发吗?

urls.py

    re_path(r'ceshi_uwsgi',view=views.test),
    re_path(r'ceshi_uwsgi2',view=views.test),

views.py

def test(request):
    time.sleep(5)
    return HttpResponse('ok')
def test2(request):
    time.sleep(5)
    return HttpResponse('ok')

启动方式

python manage.py runserver 0:8002

例 1:当我快速在浏览器两个窗口分别输入

http://localhost:8002/publisher/ceshi_uwsgi
http://localhost:8002/publisher/ceshi_uwsgi

给我的反应是一个窗口请求 5 秒执行完后再执行另外一个窗口请求,总共 10 秒

例 2:当我快速在浏览器两个窗口分别输入

http://localhost:8002/publisher/ceshi_uwsgi
http://127.0.0.1:8002/publisher/ceshi_uwsgi

给我的反应是基本上是同时执行 请求总共 5 秒中

我所理解的并发是 django 一个单线程的程序,一个请求没有结束是不能开始第二个请求(换句话就是不能并发),我后来给 django 配置了 uwsgi 服务器,结果还是像上述一样,我不太理解为什么会出现上面这种情况,希望大佬可以指点一二,感谢


Python中Django默认支持并发吗?

26 回复

我希望在两个请求基本上同时发生的情况下,同时结束(能够并发),怎么实现它


Django本身是同步框架,默认不支持并发处理请求。每个请求会阻塞工作进程直到完成,这是WSGI服务器的典型行为。

不过有几种方式实现并发:

  1. WSGI服务器多进程/多线程:像Gunicorn或uWSGI这样的生产服务器,可以通过配置工作进程(workers)或线程来处理并发请求。例如用Gunicorn启动:gunicorn --workers=4 myproject.wsgi

  2. ASGI支持:Django 3.0+原生支持ASGI,配合Uvicorn或Daphne等异步服务器,可以处理异步视图和并发请求。

  3. 异步视图:Django 3.1+支持异步视图,在ASGI服务器下可以并发处理多个异步请求。

简单说,Django应用本身的并发能力取决于部署的服务器配置,而不是框架默认提供。

总结:用生产级WSGI/ASGI服务器并配置多worker来实现并发。

请使用专业的工具测试,比如 ab,Chrome 访问两个相同的地址,会在一个加载完毕后再加载另外一个。

你 uwsgi 配置多个进程多个线程,就支持并发了,默认单进程单线程跑应该还是没并发的。

Python 是有个全局锁,所以 Python 的应用一般是多进程部署,要想彻底搞明白这个问题,先搞定 Python 的全局锁,是什么,然后在研究一下 Django 的 python 启动模式,去官方文档里找 uwsgi 服务器的配置说明,启动完成以后,检查一下进程中是否有多个 uwsgi 进程,如果有,则是多进程启动

首先要分清 Web Server 和 Web Application 之间的区别:Web Server 可以使用多线程多线程或者是 Reactor 模型来支持并发, 前者可以支持并行, 后者因为 GIL 的原因, 只能支持并发。 而 Web Application 仅仅只是一个应用而已, 当你使用 runserver 来启动 Django 时, 其实是启动了 Django 为开发者所提供的测试 Server 而已, 并不支持并发, 请求为串行执行。 至于在配置了 uwsgi Web Server 之后还是不支持并发, 尝试将 process 配置为 CPU 核心数

生产上可以用 uwsgi+nginx

上面动不动就说 GIL 全局锁的是不是有毛病?你家网站是 CPU 密集型的?

django 自带那个是调试用的,虽然是串行,但正常人是不会将他放到生产环境的。你要并行的 uwsgi 非阻塞模式 /gunicorn 异步引擎了解一下

和 GIL 基本没关系

网络请求本身就是异步的.

楼上的不观察细节吗。两次请求的域名不一样就并发…一样就串行

Chrome 有这个毛病,同样的 URL 并发请求,如果第一无响应第二个根本不发出去

另外建议楼主在视图函数的开始和结束时分别打带时间的 Log,这才是 debug 应有的态度

django 的 runserver 是多线程的

django 文档里明确说明了 runserver 是多线程,如果想要单线程需要加参数–nothreading 为啥各位大佬都说串行……

wsgi 并发要借助 thread 和 multi-process

是吗😂平时都没留意,很多 wsgi 服务器都说要特定的引擎才能实现非阻塞,就把他套在了 runserver 上面了🙈

这个是 chrome 的问题,对同一个 url 只会在第一个请求结束之后才开始第二个请求。

Python 的多线程基本上是伪并行,可以了解一下 GIL 全局锁,就明白了,Python 的应用即便是使用了多线程,但基本上没办法处理高并发,所以一般高并发配合的必须是多进程,或者采用协程,但协程是开弓没有回头箭,一开始是协程,就要任何代码都是协程,否则性能很难保证

没法高并发是因为 python 慢,可不是因为什么全局锁。你在学习一下并发和并行的区别就明白了

既视感 两三年前有个如出一辙的帖子

另外 Python 的多线程是真的多线程, 只是有一把锁而已, 执行 Python 代码的时候要先拿到这把锁. 但是调用系统库那可是真的并行在跑


我觉得吧,您让我学习一下的建议,我会接受的,但您是否考虑一下我的建议?
1. 翻翻 Python 解释器的源码,找找 CPython 的全局锁的实现代码。
这里给您奉上:
https://github.com/python/cpython/blob/e62a694fee53ba7fc16d6afbaa53b373c878f300/Python/ceval.c#L238
2. 考虑一下解释器作为共享资源,被全局锁保护以后,多线程代码在执行的时候,是否会被同步,在临界代码执行以后,才会被释放
3. 再思考一下,在什么特殊的情况下,会主动让出全局锁
4. PyThread_type_lock 这个看一下结构体,然后呢,自己做个试验,在多线程的情况下,模拟并发耗时操作,不断调高线程数,看一下总耗时是否和线程数的增加成正相关
5. 人家说的 Django,里面基本上是 Python 代码,几乎没有 C 的扩展调用,系统库也不都是用 C 实现的,C 实现的 io 操作是使用操作系统本身的线程、进程以及信号量来处理的。

楼主,没有人会使用 Django 默认的 runserver 进行生产部署的,并且官方文档也非常不推荐在生产环境使用 runserver 进行部署,原因就是 Python 虽然可以多线程,但是因为 CIL 的存在,导致其并发效率非常低,至于为什么很低,我前面已经把关键点罗列了一下。
生产环境部署 Python 的 Web 应用,有两种方式,一种是 uwsgi 使用多进程,多开 work,进行部署,一种是使用 gevent 协程实现非阻塞异步 I/O,但是我前面说了,这种要求,其他的代码也必须是非阻塞的编程模型。跟 nodejs 一样。
说的 runserver 是多线程的没有什么问题,能解决您的测试疑惑,但这里面最本质的还是要考虑,CIL 到底对并发有多大影响,GIL 一直起作用的时候,线程需要不断等待获取 GIL,线程被同步,但 I/O 操作的时候,Python 代码是会让出全局锁的,所以,多线程是有效的,可以考虑使用,但前提这是非阻塞的 I/O,也就说,C 底层提供的 I/O 功能,或者用 C 实现的非阻塞 I/O 功能,uwsgi 虽然是 C 写的,但不是非阻塞的,可以查看一下 C 的源码,如果不设置多个 work,就不能处理高并发,可以压测一下。试试

你这不也承认多线程是有用的吗,还有什么好抬杠的。网站就是一个网络数据的处理,c 单线程估计也能完爆多线程的 python,python 的协程估计比多线程还强,这里面的思想不就是让 CPU 一直跑着去 handle 数据?数据流动比 CPU 处理速度慢多了


前提都看不懂么?在非阻塞的情况下多线程能处理并发,阻塞代码基本上多线程没用
什么 C 单线程完爆 Python 多线程,还估计,说的是 C 的非阻塞 IO 代码能交还 GIL,不会引起 Python 多线程的同步等待,这也是 Python 伪并发的原因
这里的思想是 CPU 跑着 handle 数据?想表达什么?
数据流动比 CPU 处理速度快?数据流动是什么?

有大佬开多一个贴再说明说明吗?

回到顶部