V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
lanqing
V2EX  ›  Python

初学 django,django 默认能否并发?

  •  
  •   lanqing · 2018-11-21 14:44:24 +08:00 · 11314 次点击
    这是一个创建于 2226 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 服务器,结果还是像上述一样,我不太理解为什么会出现上面这种情况,希望大佬可以指点一二,感谢

    第 1 条附言  ·  2018-11-22 10:17:23 +08:00

    非常感谢各位的回复!

    有个朋友的回答,我觉得回答的挺好的,就是那个11111111的朋友..

    我查了一下官方文档

    (django==2.1)
    --nothreading
    Disables use of threading in the development server. The server is multithreaded by default.
    

    django默认是多线程的,应该是支持并发,只不过没有uwsgi+nginx支持的好而已

    还有google浏览器第一个访问没进去,第二个是不会响应的(我没仔细测试,但是应该是对的..)

    非常感谢

    26 条回复    2018-12-05 14:43:30 +08:00
    lanqing
        1
    lanqing  
    OP
       2018-11-21 14:45:52 +08:00
    我希望在两个请求基本上同时发生的情况下,同时结束(能够并发),怎么实现它
    Acebiu
        2
    Acebiu  
       2018-11-21 14:54:48 +08:00 via Android
    请使用专业的工具测试,比如 ab,Chrome 访问两个相同的地址,会在一个加载完毕后再加载另外一个。
    scriptB0y
        3
    scriptB0y  
       2018-11-21 14:55:20 +08:00
    你 uwsgi 配置多个进程多个线程,就支持并发了,默认单进程单线程跑应该还是没并发的。
    Neojoke
        4
    Neojoke  
       2018-11-21 15:42:00 +08:00
    Python 是有个全局锁,所以 Python 的应用一般是多进程部署,要想彻底搞明白这个问题,先搞定 Python 的全局锁,是什么,然后在研究一下 Django 的 python 启动模式,去官方文档里找 uwsgi 服务器的配置说明,启动完成以后,检查一下进程中是否有多个 uwsgi 进程,如果有,则是多进程启动
    SmartKeyerror
        5
    SmartKeyerror  
       2018-11-21 19:25:28 +08:00
    首先要分清 Web Server 和 Web Application 之间的区别:Web Server 可以使用多线程多线程或者是 Reactor 模型来支持并发, 前者可以支持并行, 后者因为 GIL 的原因, 只能支持并发。 而 Web Application 仅仅只是一个应用而已, 当你使用 runserver 来启动 Django 时, 其实是启动了 Django 为开发者所提供的测试 Server 而已, 并不支持并发, 请求为串行执行。 至于在配置了 uwsgi Web Server 之后还是不支持并发, 尝试将 process 配置为 CPU 核心数
    Nick2VIPUser
        6
    Nick2VIPUser  
       2018-11-21 21:19:59 +08:00   ❤️ 1
    生产上可以用 uwsgi+nginx
    lfzyx
        7
    lfzyx  
       2018-11-21 21:26:27 +08:00   ❤️ 4
    上面动不动就说 GIL 全局锁的是不是有毛病?你家网站是 CPU 密集型的?
    FullBridgeRect
        8
    FullBridgeRect  
       2018-11-21 21:53:45 +08:00 via Android
    django 自带那个是调试用的,虽然是串行,但正常人是不会将他放到生产环境的。你要并行的 uwsgi 非阻塞模式 /gunicorn 异步引擎了解一下
    laike9m
        9
    laike9m  
       2018-11-21 21:56:57 +08:00
    @Neojoke 和 GIL 基本没关系
    ltoddy
        10
    ltoddy  
       2018-11-21 21:57:17 +08:00
    网络请求本身就是异步的.
    111111111111
        11
    111111111111  
       2018-11-21 22:00:22 +08:00 via Android
    楼上的不观察细节吗。两次请求的域名不一样就并发…一样就串行

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

    另外建议楼主在视图函数的开始和结束时分别打带时间的 Log,这才是 debug 应有的态度
    111111111111
        12
    111111111111  
       2018-11-21 22:01:24 +08:00 via Android
    @FullBridgeRect django 的 runserver 是多线程的
    111111111111
        13
    111111111111  
       2018-11-21 22:13:14 +08:00 via Android
    django 文档里明确说明了 runserver 是多线程,如果想要单线程需要加参数--nothreading 为啥各位大佬都说串行……
    ericls
        14
    ericls  
       2018-11-22 00:10:49 +08:00
    wsgi 并发要借助 thread 和 multi-process
    FullBridgeRect
        15
    FullBridgeRect  
       2018-11-22 01:24:26 +08:00 via Android
    @111111111111 是吗😂平时都没留意,很多 wsgi 服务器都说要特定的引擎才能实现非阻塞,就把他套在了 runserver 上面了🙈
    Trim21
        16
    Trim21  
       2018-11-22 01:53:34 +08:00 via Android
    这个是 chrome 的问题,对同一个 url 只会在第一个请求结束之后才开始第二个请求。
    Neojoke
        17
    Neojoke  
       2018-11-22 09:02:35 +08:00
    @111111111111 Python 的多线程基本上是伪并行,可以了解一下 GIL 全局锁,就明白了,Python 的应用即便是使用了多线程,但基本上没办法处理高并发,所以一般高并发配合的必须是多进程,或者采用协程,但协程是开弓没有回头箭,一开始是协程,就要任何代码都是协程,否则性能很难保证
    petelin
        18
    petelin  
       2018-11-22 09:29:53 +08:00 via iPhone
    @Neojoke 没法高并发是因为 python 慢,可不是因为什么全局锁。你在学习一下并发和并行的区别就明白了
    hljjhb
        19
    hljjhb  
       2018-11-22 09:51:07 +08:00 via Android
    既视感 两三年前有个如出一辙的帖子
    111111111111
        20
    111111111111  
       2018-11-22 11:00:06 +08:00 via Android
    @Neojoke

    In CPython, due to the Global Interpreter Lock,.....
    However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.
    petelin
        21
    petelin  
       2018-11-22 17:40:33 +08:00
    @Neojoke 另外 Python 的多线程是真的多线程, 只是有一把锁而已, 执行 Python 代码的时候要先拿到这把锁. 但是调用系统库那可是真的并行在跑
    Neojoke
        22
    Neojoke  
       2018-11-22 18:11:24 +08:00
    @petelin
    我觉得吧,您让我学习一下的建议,我会接受的,但您是否考虑一下我的建议?
    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 操作是使用操作系统本身的线程、进程以及信号量来处理的。
    Neojoke
        23
    Neojoke  
       2018-11-22 18:32:20 +08:00
    楼主,没有人会使用 Django 默认的 runserver 进行生产部署的,并且官方文档也非常不推荐在生产环境使用 runserver 进行部署,原因就是 Python 虽然可以多线程,但是因为 CIL 的存在,导致其并发效率非常低,至于为什么很低,我前面已经把关键点罗列了一下。
    生产环境部署 Python 的 Web 应用,有两种方式,一种是 uwsgi 使用多进程,多开 work,进行部署,一种是使用 gevent 协程实现非阻塞异步 I/O,但是我前面说了,这种要求,其他的代码也必须是非阻塞的编程模型。跟 nodejs 一样。
    @111111111111 说的 runserver 是多线程的没有什么问题,能解决您的测试疑惑,但这里面最本质的还是要考虑,CIL 到底对并发有多大影响,GIL 一直起作用的时候,线程需要不断等待获取 GIL,线程被同步,但 I/O 操作的时候,Python 代码是会让出全局锁的,所以,多线程是有效的,可以考虑使用,但前提这是非阻塞的 I/O,也就说,C 底层提供的 I/O 功能,或者用 C 实现的非阻塞 I/O 功能,uwsgi 虽然是 C 写的,但不是非阻塞的,可以查看一下 C 的源码,如果不设置多个 work,就不能处理高并发,可以压测一下。试试
    petelin
        24
    petelin  
       2018-11-22 18:58:42 +08:00 via iPhone
    @Neojoke 你这不也承认多线程是有用的吗,还有什么好抬杠的。网站就是一个网络数据的处理,c 单线程估计也能完爆多线程的 python,python 的协程估计比多线程还强,这里面的思想不就是让 CPU 一直跑着去 handle 数据?数据流动比 CPU 处理速度慢多了
    Neojoke
        25
    Neojoke  
       2018-11-22 21:18:36 +08:00 via iPhone
    @petelin
    前提都看不懂么?在非阻塞的情况下多线程能处理并发,阻塞代码基本上多线程没用
    什么 C 单线程完爆 Python 多线程,还估计,说的是 C 的非阻塞 IO 代码能交还 GIL,不会引起 Python 多线程的同步等待,这也是 Python 伪并发的原因
    这里的思想是 CPU 跑着 handle 数据?想表达什么?
    数据流动比 CPU 处理速度快?数据流动是什么?
    YuanGu333
        26
    YuanGu333  
       2018-12-05 14:43:30 +08:00
    有大佬开多一个贴再说明说明吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1747 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 16:36 · PVG 00:36 · LAX 08:36 · JFK 11:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.