今天在学python协程的时候有一些疑惑,向源源大神请教了一下,学到好多,总结一下。
python是线程安全的
python语言的基本数据结构设定的时候就是线程安全的,一个线程执行的时候,会有GIL锁,别的线程拿不到锁无法执行,所以python没办法多线程并发。所以python的多线程是个特例。
CPU的最小调度单元是线程不是进程,所以单进程多线程也可以利用多核CPU
以前学操作系统的时候,记得CPU一次只能执行一个进程,别的进程只能等待。没有错,但是要明确一点 “CPU的最小调度单元是线程不是进程”。
项目一般分类为计算密集型和IO密集型
对于I/O密集型,一般不会用python做,因为不能用多线程。
对于异步I/O,虽然不能利用多线程,但是可以利用协程
python2的gevent或是greenlet库是python3的async io出来前的协程解决方案
但是gevent和greenlet的学习成本比较大,对于I/O密集型可以选择golang。
golang的语言特性
goalng没有多进程,它是单进程:m线程:n协程的结构,由于CPU的执行最小单元是线程,所以golang可以有效利用多核。但是golang的基础数据结构比如map就不是线程安全,有时候要考虑加锁。那么在加锁的情况下,golang其实这段代码其实同时只有一个协程可以跑。
golang的协程
golang的goroutine是语言自带的协程,实现起来没有历史包袱,可以有效的利用多核,在一些新内核特性的支持下,它的I/O处理性能可以非常恐怖。并且编程复杂度也不是很高。
协程
一般来说协程都是n:m的协程,即n个协程在m个线程里跑,有一个runtime协程作为调度,所以可以有效利用多核。
但是python的协程是n:1的协程,即n个协程在1个线程里跑,可以实现异步I/O,但是不能有效利用多核。
对于I/O 密集型,python可以利用协程来解决,有非阻塞I/O,不需要多核,比如node就是计算单线程,I/O用的内部的线程池。Python加入async io后,可能会对一些场景下的io性能有提升
python的协程库
gevent(greenlet)应该可以用n:m协程模式。python把输入给gevent模块,gevent自己里面的C模块调用新的一套进程线程模式,把结果返回给python。所谓的n:m指的是gevent里的实现,跟python没什么关系,是透明的,所以可以是n:m模式。(所谓“语言的扩展”用另一门语言来扩充当前语言的语法,相当与你扩充了Python的语法用法特性)
库
库分为原生的和二进制封装的。原生代码就是说用Python写了一个Python库,然后用Python执行它,它的所有特性都在Python解释器的语法用法范围内。但是也可以用C写一个Python库,编译成动态链接库,然后在Python里面执行它,执行到这个库的时候,逻辑就到了的动态链接库里,这个时候Python解释器是控制不了的,也就相当与扩充了Python的语法用法特性。平常所见的NumPy,Gevent,TensorFlow都是后者。
对于计算密集型
对于计算密集型,python和node之类的就要利用多进程来弥补计算资源的不足,但是golang多线程就会比较自然了。
由一个协程问题请教了这么多,不是说golang比python好,只是在某些特性方面各有利弊。python类似一个胶水语言,简单易学易上手,入手快,不用编译,脚本型语言,然后在高性能库/应用中间做一个胶水。但是这么好上手还是学起来。
最后发个源源大神爱的抱抱~ 笔芯~ 💖💖💖💖💖💖💖💖💖💖