1
cheetah 2017-10-08 22:23:20 +08:00
是两种异步方案
|
2
hjc4869 2017-10-08 22:31:03 +08:00
有 urllib,为什么还要 urllib2 呢?
|
3
PythonAnswer 2017-10-08 22:33:12 +08:00
asyncio 是基于 yield 的
thread 受限于 gil, 用处不大 |
4
testcount 2017-10-08 23:06:58 +08:00 via Android
线程和协程
|
5
Kilerd 2017-10-08 23:21:11 +08:00
多进程,线程,协程,异步
这四个概念先懂了,我们再来聊聊这个问题。 |
6
DoctorCat 2017-10-08 23:23:58 +08:00
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. [] 里的含义,了解下相信你就明白了。 |
7
Srar 2017-10-08 23:42:24 +08:00
虽然没写过 Python 但是还是来回答下...是来降低上下文切换所带来的性能损失.
|
8
aijam 2017-10-09 00:16:39 +08:00 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,说明社区还在努力探索。 |
9
NoAnyLove 2017-10-09 00:42:29 +08:00 1
#3 楼的回答过于偏颇。并没有受限于 GIL 就让 thread 用处不大这种说法了,具体还是看应用场景,如果是计算密集的任务,为了充分利用多核,当然不会用 thread,而应该用 process。但是对于 IO 密集场景或者仅仅为了解决多路传输,那么 thread 是简单而有效的选择。而且#3 楼将两句话并发在一起,新手会以为 asyncio 不受限于 GIL 能够处理计算密集的任务。
个人认为,两者的主要差别是可以处理并发量的能力。可以根据你需要处理的异步 IO 的数量,比如:如果有 100 个 socket,那么给每个 socket 分别创建一个 thread 来处理,现在的计算机应该都能 hold 住。但是当 socket 数量更高,并发量更大的时候,那么就应该选择使用 asyncio 了。 |
10
keysona 2017-10-09 01:06:30 +08:00
楼上两位说得很好了。
一言不合就说 GIL 也是够了... &t=1141s 也要看看使用场景好吗... |
11
dzmcs 2017-10-09 02:24:51 +08:00 via iPad
@DoctorCat 方括号里说 io 复用,这个 asyncio 也是类似 epoll 可以得到网卡中断事件?如果只是在解释器内模拟,那这个东西做 io 大的并发估计也就一般吧
thread 是否是系统线程,进入调度队列? |
12
scriptB0y 2017-10-09 07:55:04 +08:00 1
|
13
billion 2017-10-09 09:15:12 +08:00 4
比如你需要做三件事情,用电饭煲煮饭,用洗衣机洗衣服,用砂锅煲汤。
如果你用 thread,那么就需要三个人,第一个人把饭放进电饭煲,然后等着它煮好。第二个人把衣服放进洗衣机,等着它洗好,第三个人把食材放进砂锅,等着汤煲好。准备工作做完以后,这三个人都会啥事不干,傻等着。 如果你用 asyncio,那么你只需要一个人做这个事情。他先把米倒进电饭煲,打开开关开始煮饭,煮饭的过程电饭煲自己会做,不用这个人来管。所以中间的时间,他可以接下来去把衣服放进洗衣机,打开开关,洗衣机自动开始洗衣服,也不再需要他管了。于是他再去把食材放进砂锅,开始煲汤。开始煲汤以后,短时间里他还可以去看个书。如果汤漫出来了,它会听到声音,这个时候再去查看就好了。同样的,电饭煲煮饭煮好了会有提示音,洗衣机洗好了衣服也有提示音。它只需要听到提示音再去处理就好了。没有听到提示音,他就可以去做其他事情。 综上所述, 用 thread,做多少个事情就需要请多少个人,而且还有可能这些人会同时傻等,每一个人工资(占用的系统资源)可不便宜 用 asyncio,只需要一个人就可以把所有事情全部做完。 |
15
fy 2017-10-09 09:31:40 +08:00
GIL 日常背锅
|
16
PythonAnswer 2017-10-09 10:28:22 +08:00 via Android
thread threading 就是被 gil 搞得没人用的,俺说错了?
|
17
czheo 2017-10-09 10:31:13 +08:00
@PythonAnswer 你说的没有错。
|
18
fy 2017-10-09 10:40:08 +08:00
@PythonAnswer 说的没有错,但是一 thread 并不是没人用,二在这个与 asyncio 比的场景,GIL 没锅
|
19
fy 2017-10-09 10:40:57 +08:00
应该说不能说全错
|
20
PythoneerDev6 2017-10-09 15:55:08 +08:00
GIL 日常锅
|
21
wizardforcel 2017-10-09 21:09:46 +08:00 via Android
@dzmcs 是系统级线程,但是只能映射到单个核。
|
22
wizardforcel 2017-10-09 21:12:27 +08:00 via Android
@dzmcs 虽然都只能利用单个核,但是 asyncio 没有上下文切换,优势在这里。
|
23
wizardforcel 2017-10-09 21:18:09 +08:00 via Android
另外 asyncio 也有缺陷。就是你如果用了它,所有 io api 都要用异步(支持多路复用)的版本。要不然还是卡着。这就意味着可能很多库就不能用了。
|
24
dzmcs 2017-10-09 21:30:39 +08:00 via iPad
@wizardforcel 看了下 thread 实现,是模拟线程,不是系统级线程,至少 2.7 的实现是模拟的
|
25
NoAnyLove 2017-10-09 23:18:22 +08:00
@PythonAnswer 不要总是甩锅给 GIL,到底是怎么得出结论没人用 threading 的啊?
@wizardforcel 如果没有对应的 aio 库,把同步的操作丢给线程池来处理也是可以的。目前的异步文件操作( aiofile ),DNS 查询等操作,其实都是放在线程池里面的。真正能够高效处理的还是只有 socket。 @dzmcs 不知道该说些什么。。。。。。 |
26
DoctorCat 2017-10-09 23:33:47 +08:00
@dzmcs 除了 opcode 外我大 Py 从来都不自己模拟东西好伐,至少在 Linux 下都是依赖 syscall 的。所以 thread 也是 syscall,只是从 VM 层面和开发者层面封装了一些,同时也加锁保护 VM 执行栈,所以才有了 GIL。
可以具体看一下模块源码,不是特别难懂的。 |
27
DoctorCat 2017-10-09 23:44:10 +08:00
@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 实现的 |
28
guyskk0x0 2017-10-09 23:51:46 +08:00 via Android
程序通常会遇到三种瓶颈:CPU,IO,内存
对策也有三种:多进程,多线程,异步 io/协程 多进程能利用多核 CPU,但内存开销大。 多线程在操作系统层面可以利用多核 CPU,但各种线程同步 /锁的问题,会导致 Python 解释器实现特别复杂,所以干脆加了个全局锁,只允许用一个核;线程在执行 io 操作阻塞时,系统会把线程挂起,把 CPU 分配给别的线程运行;内存开销比进程小。 异步 io 相当于在 Python 中实现 asyncio/协程相当于在 python 中实现一个内核 /调度系统,协程在进行 io 阻塞时,安排别的协程继续运行;内存开销更小。 如果你遇到 io 瓶颈,可以用多线程和协程,协程内存开销更小,能同时跑更多任务,web 服务能同时处理更多请求。 PS:asyncio 实现过于复杂,推荐 curio ! |
29
guyskk0x0 2017-10-09 23:58:20 +08:00 via Android
@wizardforcel 会 io 阻塞但没有异步 io 实现的库,可以用线程池封装成异步,也就是异步 io 和多线程可以一起用:P
|
30
dzmcs 2017-10-10 01:01:35 +08:00 via iPad
@DoctorCat
我错了 看了 threadmodule.c,没有 grep 到 pthread_create,看文件又这么长,以为是模拟的线程 是系统线程,那为啥老说 python 线程性能差呢? |
31
PythonAnswer 2017-10-10 01:31:32 +08:00 via Android
thread 模块被更高级的 threading 模块代替了。
由于 gil 的存在,threading 并不能提高 cpu 密集运算的性能。threading 以前用于提高 io 密集型的操作速度。 py3 新加的 asyncio 是用来做异步 io 的。 我很久没用 threading 了,并没有不适。 |
34
wizardforcel 2017-10-10 14:34:18 +08:00
@dzmcs 因为系统级线程和处理机(核)之间还有个映射,GIL 把这些线程都限制在一个核上了。
|