回复内容:
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
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。如果要用并发处理,基本上使用 非阻塞多路复用+多进程 方式,就可以处理绝大多数需求了