V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
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
liudaqi
V2EX  ›  Python

Python 有 thread,为什么还要 asyncio 呢?

  •  
  •   liudaqi · Oct 8, 2017 via Android · 13402 views
    This topic created in 3128 days ago, the information mentioned may be changed or developed.
    偶尔会用到 thread 做异步任务,没想到什么时候用 asyncio,这两个异步有什么差别吗,理解的不是很清楚
    35 replies    2017-10-10 22:39:38 +08:00
    cheetah
        1
    cheetah  
       Oct 8, 2017
    是两种异步方案
    hjc4869
        2
    hjc4869  
       Oct 8, 2017
    有 urllib,为什么还要 urllib2 呢?
    PythonAnswer
        3
    PythonAnswer  
       Oct 8, 2017
    asyncio 是基于 yield 的
    thread 受限于 gil, 用处不大
    testcount
        4
    testcount  
       Oct 8, 2017 via Android
    线程和协程
    Kilerd
        5
    Kilerd  
       Oct 8, 2017
    多进程,线程,协程,异步

    这四个概念先懂了,我们再来聊聊这个问题。
    DoctorCat
        6
    DoctorCat  
       Oct 8, 2017
    asyncio: This module provides infrastructure for writing [single-threaded concurrent code using coroutines, multiplexing I/O] access over sockets and other resources, running network clients and servers, and other related primitives.

    thread: This module provides low-level primitives for working with [multiple threads (also called light-weight processes or tasks) ] — multiple threads of control sharing their global data space. For synchronization, simple locks (also called mutexes or binary semaphores) are provided.

    [] 里的含义,了解下相信你就明白了。
    Srar
        7
    Srar  
       Oct 8, 2017
    虽然没写过 Python 但是还是来回答下...是来降低上下文切换所带来的性能损失.
    aijam
        8
    aijam  
       Oct 9, 2017   ❤️ 4
    1. 虽然大家(包括楼上的 @PythonAnswer )都说 thread 受限于 GIL,但是那是对 CPU bounded tasks 而言,大多情况下 thread 还是足以应付 IO bounded tasks。
    2. 即使如此,应付 IO bounded tasks 时,thread 也存在两个问题,一是 thread overhead 开销较大,二是受到系统 max thread number 的限制。基于 coroutine 的 asyncio 有助于克服这两个问题。
    3. 然而 asyncio 复杂的 API 还是被人诟病: https://twitter.com/mitsuhiko/status/792441114561220609
    最近几年 Python3.4 以后的几个新特性都是围绕基于 coroutine 的 concurrency ( async generator in 3.6, async/await in 3.5, asyncio in 3.4 ),各个 Python 的会议也都会有关于 concurrency 话题的 talk,说明社区还在努力探索。
    NoAnyLove
        9
    NoAnyLove  
       Oct 9, 2017   ❤️ 1
    #3 楼的回答过于偏颇。并没有受限于 GIL 就让 thread 用处不大这种说法了,具体还是看应用场景,如果是计算密集的任务,为了充分利用多核,当然不会用 thread,而应该用 process。但是对于 IO 密集场景或者仅仅为了解决多路传输,那么 thread 是简单而有效的选择。而且#3 楼将两句话并发在一起,新手会以为 asyncio 不受限于 GIL 能够处理计算密集的任务。

    个人认为,两者的主要差别是可以处理并发量的能力。可以根据你需要处理的异步 IO 的数量,比如:如果有 100 个 socket,那么给每个 socket 分别创建一个 thread 来处理,现在的计算机应该都能 hold 住。但是当 socket 数量更高,并发量更大的时候,那么就应该选择使用 asyncio 了。
    keysona
        10
    keysona  
       Oct 9, 2017
    楼上两位说得很好了。

    一言不合就说 GIL 也是够了...

    &t=1141s

    也要看看使用场景好吗...
    dzmcs
        11
    dzmcs  
       Oct 9, 2017 via iPad
    @DoctorCat 方括号里说 io 复用,这个 asyncio 也是类似 epoll 可以得到网卡中断事件?如果只是在解释器内模拟,那这个东西做 io 大的并发估计也就一般吧

    thread 是否是系统线程,进入调度队列?
    scriptB0y
        12
    scriptB0y  
       Oct 9, 2017   ❤️ 1
    billion
        13
    billion  
       Oct 9, 2017   ❤️ 4
    比如你需要做三件事情,用电饭煲煮饭,用洗衣机洗衣服,用砂锅煲汤。

    如果你用 thread,那么就需要三个人,第一个人把饭放进电饭煲,然后等着它煮好。第二个人把衣服放进洗衣机,等着它洗好,第三个人把食材放进砂锅,等着汤煲好。准备工作做完以后,这三个人都会啥事不干,傻等着。

    如果你用 asyncio,那么你只需要一个人做这个事情。他先把米倒进电饭煲,打开开关开始煮饭,煮饭的过程电饭煲自己会做,不用这个人来管。所以中间的时间,他可以接下来去把衣服放进洗衣机,打开开关,洗衣机自动开始洗衣服,也不再需要他管了。于是他再去把食材放进砂锅,开始煲汤。开始煲汤以后,短时间里他还可以去看个书。如果汤漫出来了,它会听到声音,这个时候再去查看就好了。同样的,电饭煲煮饭煮好了会有提示音,洗衣机洗好了衣服也有提示音。它只需要听到提示音再去处理就好了。没有听到提示音,他就可以去做其他事情。

    综上所述,
    用 thread,做多少个事情就需要请多少个人,而且还有可能这些人会同时傻等,每一个人工资(占用的系统资源)可不便宜
    用 asyncio,只需要一个人就可以把所有事情全部做完。
    jin6220
        14
    jin6220  
       Oct 9, 2017 via iPhone
    @billion 除了傻等 工作干完就不在占资源了吧 看来没必要学 thread 啊
    fy
        15
    fy  
       Oct 9, 2017
    GIL 日常背锅
    PythonAnswer
        16
    PythonAnswer  
       Oct 9, 2017 via Android
    thread threading 就是被 gil 搞得没人用的,俺说错了?
    czheo
        17
    czheo  
       Oct 9, 2017
    @PythonAnswer 你说的没有错。
    fy
        18
    fy  
       Oct 9, 2017
    @PythonAnswer 说的没有错,但是一 thread 并不是没人用,二在这个与 asyncio 比的场景,GIL 没锅
    fy
        19
    fy  
       Oct 9, 2017
    应该说不能说全错
    PythoneerDev6
        20
    PythoneerDev6  
       Oct 9, 2017
    GIL 日常锅
    wizardforcel
        21
    wizardforcel  
       Oct 9, 2017 via Android
    @dzmcs 是系统级线程,但是只能映射到单个核。
    wizardforcel
        22
    wizardforcel  
       Oct 9, 2017 via Android
    @dzmcs 虽然都只能利用单个核,但是 asyncio 没有上下文切换,优势在这里。
    wizardforcel
        23
    wizardforcel  
       Oct 9, 2017 via Android
    另外 asyncio 也有缺陷。就是你如果用了它,所有 io api 都要用异步(支持多路复用)的版本。要不然还是卡着。这就意味着可能很多库就不能用了。
    dzmcs
        24
    dzmcs  
       Oct 9, 2017 via iPad
    @wizardforcel 看了下 thread 实现,是模拟线程,不是系统级线程,至少 2.7 的实现是模拟的
    NoAnyLove
        25
    NoAnyLove  
       Oct 9, 2017
    @PythonAnswer 不要总是甩锅给 GIL,到底是怎么得出结论没人用 threading 的啊?

    @wizardforcel 如果没有对应的 aio 库,把同步的操作丢给线程池来处理也是可以的。目前的异步文件操作( aiofile ),DNS 查询等操作,其实都是放在线程池里面的。真正能够高效处理的还是只有 socket。

    @dzmcs 不知道该说些什么。。。。。。
    DoctorCat
        26
    DoctorCat  
       Oct 9, 2017
    @dzmcs 除了 opcode 外我大 Py 从来都不自己模拟东西好伐,至少在 Linux 下都是依赖 syscall 的。所以 thread 也是 syscall,只是从 VM 层面和开发者层面封装了一些,同时也加锁保护 VM 执行栈,所以才有了 GIL。

    可以具体看一下模块源码,不是特别难懂的。
    DoctorCat
        27
    DoctorCat  
       Oct 9, 2017
    @dzmcs 回复 24 楼的观点,我不清楚你所谓的 [模拟] 指的是啥,但可以看看代码: https://github.com/python/cpython/blob/master/Modules/_threadmodule.c#L1023
    https://github.com/python/cpython/blob/731e18901484c75b60167a06a0ba0719a6d4827d/Python/thread_pthread.h#L201
    Linux 下是 pthread 实现的
    guyskk0x0
        28
    guyskk0x0  
       Oct 9, 2017 via Android
    程序通常会遇到三种瓶颈:CPU,IO,内存
    对策也有三种:多进程,多线程,异步 io/协程

    多进程能利用多核 CPU,但内存开销大。

    多线程在操作系统层面可以利用多核 CPU,但各种线程同步 /锁的问题,会导致 Python 解释器实现特别复杂,所以干脆加了个全局锁,只允许用一个核;线程在执行 io 操作阻塞时,系统会把线程挂起,把 CPU 分配给别的线程运行;内存开销比进程小。

    异步 io 相当于在 Python 中实现
    asyncio/协程相当于在 python 中实现一个内核 /调度系统,协程在进行 io 阻塞时,安排别的协程继续运行;内存开销更小。

    如果你遇到 io 瓶颈,可以用多线程和协程,协程内存开销更小,能同时跑更多任务,web 服务能同时处理更多请求。

    PS:asyncio 实现过于复杂,推荐 curio !
    guyskk0x0
        29
    guyskk0x0  
       Oct 9, 2017 via Android
    @wizardforcel 会 io 阻塞但没有异步 io 实现的库,可以用线程池封装成异步,也就是异步 io 和多线程可以一起用:P
    dzmcs
        30
    dzmcs  
       Oct 10, 2017 via iPad
    @DoctorCat
    我错了
    看了 threadmodule.c,没有 grep 到 pthread_create,看文件又这么长,以为是模拟的线程
    是系统线程,那为啥老说 python 线程性能差呢?
    PythonAnswer
        31
    PythonAnswer  
       Oct 10, 2017 via Android
    thread 模块被更高级的 threading 模块代替了。

    由于 gil 的存在,threading 并不能提高 cpu 密集运算的性能。threading 以前用于提高 io 密集型的操作速度。

    py3 新加的 asyncio 是用来做异步 io 的。

    我很久没用 threading 了,并没有不适。
    DoctorCat
        32
    DoctorCat  
       Oct 10, 2017
    @dzmcs 据说单核那个年代 Guido 在设计时偷懒了加了 GIL,没考虑过多核…
    justff
        33
    justff  
       Oct 10, 2017
    @DoctorCat 一直很费解,为什么这么多年了都不改进 cPython 的解释器
    wizardforcel
        34
    wizardforcel  
       Oct 10, 2017
    @dzmcs 因为系统级线程和处理机(核)之间还有个映射,GIL 把这些线程都限制在一个核上了。
    DoctorCat
        35
    DoctorCat  
       Oct 10, 2017
    @justff 社区有人尝试过的,都没啥成效。别指望 CPython 改了。
    其实放在 Web 开发领域也并无大碍,毕竟也胶水语言,可以放到本地线程栈去做计算密集,比如用 Cython 重写部分业务代码。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   787 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 68ms · UTC 20:20 · PVG 04:20 · LAX 13:20 · JFK 16:20
    ♥ Do have faith in what you're doing.