伴随着多核时代的到来,怎样充分利用好你的多个CPU的优势成了

技术的关注点,那就是多线程多进程

编程,二者的区别也很明显,进程是操作系统中拥有资源的最小单位,但是是重量级的。线程是系统调度的最小单位,是轻量级的,一个进程可以拥有很多个线程,但是线程是不拥有资源的,同一个进程中的线程共享这个进程中拥有的资源。以前学习java,一个灰常重要的并发方式就是多线程,因为线程的开销要比进程的少很多,而通过加锁来保证线程

安全,进而有线程池来做进一步的

优化。

python的多线程编程进行了了解,然后又了解了一下python的第三方库线程池threadpool。但是了解后面发现这些都白费了,虽然python提供了thread和threading库来支持多线程的实现,但是python最终还是没办法达到多线程并发的,原因就是GIL。

        网上关于GIL的讨论也有很多,我也做了进一步的了解,这里有个例子可以看一下,就是python一个线程的死循环和开启多个线程来执行死循环对于CPU的消耗是差不多的,我的电脑是双核的,来测试一把:

程序运行前cpd的使用率:

主线程执行死循环cpu的使用率:

开一个线程来执行死循环,主线程也执行死循环cpu的使用率:

原因就是GIL。

1.何方神圣

        GIL全称是Global Interpreter Lock,即全局解释锁,每个python解释器都有一个这样的全局锁,在解释器解释执行任何的python代码都要先获得这个锁。所以同一时间只有一个线程持有这个锁在运行,其他的线程都在等待这个锁。所以虽然有两个线程在执行死循环,但实际上每次只有一个线程在运行。

2.要它何用

安全的,如果没有GIL,那么在多线程中一些简单的操作都会出现问题,在可见变量我们可以自行加锁,而还有很多后台不可见的变量就需要GIL来控制了,比如为了进行垃圾回收而维护的引用计数,如果没有GIL,有可能出现由于线程切换导致的对同一个对象释放两次的情况。所以有了Lock还是需要GIL的。

支持多线程并发了,曾有过官方实验发现这样的做法是得不偿失的,单线程的执行效率减慢了将近两倍,而且这样的做法却复杂了N倍,本来一个全局锁就可以解决的问题却花了N多个细微的锁来解决。所以这样是不值得的,何况python还有别的方式来实现并发。

3.有了GIL要Lock何用

        既然有了这样一个全局锁来保护了python解释器,让每次只能有一个线程能够得以执行,那么对于共享资源来说,每次也只能有一个线程来访问它,那么python提供的Lock还有用么?就比如这篇博客中第一个例子,不加锁的话结果是不可知的,但是是不会达到一百万的。这又是为什么呢,不是已经有了一个全局锁来保护共享资源吗?

安全。如果是这样的话倒也说的通,但是python的线程明明是操作系统的原生线程啊。这是为什么呢,这个问题一直困扰着我啊。

4.并发其他途径

编程,虽然进程较线程是重量级的,但是进程之间是相互独立的,不存在资源共享,所以就没有了互斥的概念,也就不需要锁了,所以还可以通过多进程+协程来实现并发的。