Python 的线程处理和协程有区别么?线程库 Eventlet、Gevent 的实现是否可以做到多个线程同时并发呢?

2019-12-28 11:36:37 +08:00
 lenqu

求大佬们给个详细的理解

5773 次点击
所在节点    Python
16 条回复
676529483
2019-12-28 11:45:03 +08:00
这个。。。你的基础差的有点多,先学习下同步异步线程协程等的概念把
wuwukai007
2019-12-28 11:48:15 +08:00
找一个爬虫异步版照着敲一遍感受一下
lenqu
2019-12-28 12:03:46 +08:00
python 的线程,python 的线程不是标准线程,在 python 中,一个进程内的多个线程只能使用一个 CPU。

如果使用 gevent 包装后的线程,程序员就不必承担调度的责任,而 python 的线程本身就没有使用多 CPU 的能力,那么,用 gevent 包装后的线程,取代 python 的内置线程,不是只有避免无意义的调度,提高性能的好处,而没有什么坏处了吗?

答案是否定的。举一个例子,有一个 GUI 程序,上面有两个按钮,一个 运算 一个 取消 ,点击运算,会有一个运算线程启动,不停的运算,点击取消,会取消这个线程,如果使用 python 的内置线程或者标准线程,都是没有问题的,即便运算线程不停的运算,调度器仍然会给 GUI 线程分配时间片,用户可以点击取消,然而,如果使用 gevent 包装后的线程就完蛋了,一旦运算开始,GUI 就会失去相应,因为那个运算线程(协程)霸着 CPU 不让位。不单是 GUI,所有和用户交互的程序都会有这个问题
lenqu
2019-12-28 12:05:09 +08:00
1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样 python 中则能使用多核 CPU。

2) 线程进程都是同步机制,而协程则是异步

3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
lenqu
2019-12-28 12:07:18 +08:00
2、多线程一般是使用 threading 库,完成一些 IO 密集型并发操作。多线程的优势是切换快,资源消耗低,但一个线程挂掉则会影响到所有线程,所以不够稳定。现实中使用线程池的场景会比较多,具体可参考 https://www.cnblogs.com/rianley/p/9076207.html

   3、协程一般是使用 gevent 库,当然这个库用起来比较麻烦,所以使用的并不是很多。相反,协程在 tornado 的运用就多得多了,使用协程让 tornado 做到单线程异步,据说还能解决 C10K 的问题。所以协程使用的地方最多的是在 web 应用上。

总结一下就是 IO 密集型一般使用多线程或者多进程,CPU 密集型一般使用多进程,强调非阻塞异步并发的一般都是使用协程,当然有时候也是需要多进程线程池结合的,或者是其他组合方式。
wzwwzw
2019-12-28 12:10:12 +08:00
看看线程,进程,协程,在看看 python 的 thread , multiprocessing, asyncio.
misaka19000
2019-12-28 12:13:51 +08:00
so1n
2019-12-28 12:23:48 +08:00
@lenqu python 的线程是标准线程,调用的是系统的线程
so1n
2019-12-28 12:25:16 +08:00
@lenqu 进程线程也可以异步……
jimages
2019-12-28 12:26:35 +08:00
从概念上讲,线程和协程是有区别的,理解为线程可以并行,协程不能并行。但是囿于 CPython 的具体实现问题( GIL )上,线程和协程在某种程度上是一致的。
线程也就是有多个执行流,由操作系统负责调度执行流,由于执行流的切换是由操作系统负责的,所以对于编程者来说是完全透明的,无感知的(除去同步问题)。同时呢,由于执行流的调度是有操作系统负责的,在 SMP 上可以实现并行运行,也就是两个线程同时运行。
但是协程也是有多个执行流,但是这个执行流是由用户来负责的,所以编程者需要大量处理协切换的问题。同时呢,由于协程是在用户的控制下进行切换。对操作系统来说,这只是一个线程。所以在 SMP 上无法享受到多线程的并发优势。
为什么在 Python 上大家一般推崇协程而不是线程呢?
线程的切换在操作系统的调度是,某一个线程运行了一段时间之后(可能是几十毫秒),这个时候就会发生调度切换。去运行其他的线程,这种频繁的线程切换实际上也是有开销的,可能会有几百个时钟周期。而这种线程切换是周期性的。所以总体来说开销还是蛮大的。
但是对于协程来说,由于协程的切换是用户控制的,那么也就是说,少去了很多不必要的线程切换,因为用户自己控制线程切换时,大概率是真的有必要切换。所以比操作系统切换来说,开销更少了,操作系统不需要再进行周期性的切换了。
youngce
2019-12-28 14:06:38 +08:00
协程的话 gevent 也已经被 asyncio 替代了,毕竟后者是标准库,而且写起来也稍微舒服一些。
ManjusakaL
2019-12-28 15:14:50 +08:00
看了下,,槽点太多一下不知道从什么地方讲起。。。
Courstick
2019-12-28 15:31:31 +08:00
w
lenqu
2019-12-28 16:44:44 +08:00
@ManjusakaL 讲一下,大佬 o
haozhang
2019-12-29 09:15:41 +08:00
1.所谓的“多个线程同时并发”其实就是并行,你可以搜索下并行 parallel 和并发 concurrency 的区别
2.进程线程是操作系统进行调度的,你无法决定哪个特定时间点运行哪个进程或者线程
3.协程是程序自行调度的,但凡是协程那么肯定已经预先写好了调度的代码,比如说 go 的协程,go 里面就已经写好了调度的逻辑代码。
4.是否能够做到并行?能的,只要没有 GIL 全局解释器锁,那么就可以并行。
cominghome
2020-01-09 21:20:34 +08:00
并发可以,并行不行

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/633072

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX