为什么有人说 Python 的多线程是鸡肋呢?

WBOY
Release: 2016-06-06 16:11:12
Original
1537 people have browsed it

回复内容:

GIL blablabla concurrent blablabla

简单地说就是作为可能是仅有的支持多线程的解释型语言(perl的多线程是残疾,PHP没有多线程),Python的多线程是有compromise的,在任意时间只有一个Python解释器在解释Python bytecode。

UPDATE:如评论指出,Ruby也是有thread支持的,而且至少Ruby MRI是有GIL的。

如果你的代码是CPU密集型,多个线程的代码 很有可能是线性执行的。所以这种情况下多线程是鸡肋,效率可能还不如单线程因为有context switch

但是:如果你的代码是IO密集型,多线程可以明显提高效率。例如制作爬虫(我就不明白为什么Python总和爬虫联系在一起…不过也只想起来这个例子…),绝大多数时间爬虫是在等待socket返回数据。这个时候C代码里是有release GIL的,最终结果是某个线程等待IO的时候其他线程可以继续执行。

反过来讲:你就不应该用Python写CPU密集型的代码…效率摆在那里…

如果确实需要在CPU密集型的代码里用concurrent,就去用multiprocessing库。这个库是基于multi process实现了类multi thread的API接口,并且用pickle部分地实现了变量共享。

再加一条,如果你不知道你的代码到底算CPU密集型还是IO密集型,教你个方法:

multiprocessing这个module有一个dummy的sub module,它是基于multithread实现了multiprocessing的API。

假设你使用的是multiprocessing的Pool,是使用多进程实现了concurrency
from multiprocessing import Pool 
Copy after login
Global Interpretor Lock在python的原始解释器CPython中存在着GIL(Global Interpreter Lock,全局解释器锁),因此在解释执行python代码时,会产生互斥锁来限制线程对共享资源的访问,直到解释器遇到I/O操作或者操作次数达到一定数目时才会释放GIL。

所以,虽然CPython的线程库直接封装了系统的原生线程,但CPython整体作为一个进程,同一时间只会有一个获得GIL的线程在跑,其他线程则处于等待状态。这就造成了即使在多核CPU中,多线程也只是做着分时切换而已。

不过muiltprocessing的出现,已经可以让多进程的python代码编写简化到了类似多线程的程度了。 有泳池一个,四个泵,但只有一个人,一人只能开启管理着其中一个,所以四个泵没什么用。
====================================================================
但是,如果泵的工作时间与冷却恢复时间是1:3(感谢 inoahx指出,已改),那么配置的利用率高达100%。(这是基于个人理解的一个比喻,如不妥,请补充)。 一般大部分的观点是由于有 GIL 的存在,Python 中的多线程不能真正的利用多核,不能解决 cpu bound 的问题,但是在一些 IO bound 的程序上却可以有很好的提升。
但是目前的情况是 我们有了 协程啊,在 2.x 系列里我们可以使用 gevent 啊,在 3.x 系列的标准库里又有了 asyncio。IO bound 的问题完全可以用协程解决。而且我们可以自主的控制协程的调度了。为什么还要使用由 OS 调度的不太可控的线程呢?
所以我认为线程在 Python 里就是个鸡肋。尤其实在 3.x 系列里。

还有一个介绍 2012 不宜进入的三个技术点(中) @yegle说的大部分都是对的。
唯有并发 I/O 的一部分…… 为什么会有“线程是为不懂状态机的程序员准备的”这种说法?在单核的计算机上编程根本不需要使用多线程编程吗?这个问题已经说了我想说的了。
并发 I/O 的情况请善用 Tornado / Gevent 这种基于库,每 CPU 核心起一个进程跑一个 event loop;除非请求的处理时间远大于 I/O 和 job scheduling 的时间,这种情况实际上也应该通过 MQ 往多机上发布任务了。 Python多线程是不是鸡肋,是,GIL那个东西再那里摆着,就算在多核下面Python也是无法并行的,这个好理解嘛,就相当于做了个分时复用。

Python多线程有没有用,有,你去爬图片站的时候,用单进程单线程这种方式,进程很容易阻塞在获取数据socket函数上,多线程可以缓解这种情况。你说解决没有,要是每个请求都阻塞起了,那多线程也没什么用(当然,这种情况没见过哈)。

Python的优势就在于写起来快,用起来方便。你要做计算密集型的,还想并行化的话,还是用C吧。 对于计算密集型的任务,多线程是鸡肋,不如用多进程,但是对于IO密集型的任务,多线程并不是鸡肋,因为网络IO的延迟比CPU的更大。 个人看法,线程本身就是一个有些复杂甚至可以说有些丑陋的解决方案,95%的情况下其实都可以不用——KISS。

如果要用并发处理,基本上使用 非阻塞多路复用+多进程 方式,就可以处理绝大多数需求了
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!