python爬虫之多线程、多进程、GIL锁

时间:2023-01-30 20:51:38

背景:

  我们知道多线程要比多进程效率更高,因为线程存在于进程之内,打开一个进程的话,首先需要开辟内存空间,占用内存空间比线程大。这样想也不怪,比如一个进程用10MB,开10个进程就得100MB的内存空间。但是我们开线程的话,只需要开通一个进程,在进程里面再开10个线程,这样的话内存空间只需要10MB就开了,这么想也是对的,但是、但是。

GIL:

  又名全局解释器锁,python在设计当初(那个年代哪来的多核,电脑都没来普及),也是python的一个设计思想,为了数据安全,怎么个为数据安全考虑呢(一个进程里面只有一个GIL锁),即同一时间只能一个事件发生,我们来捋一下请求过程,第一个线程过来拿到任务,向python申请GIL锁,拿到锁以后条用os的原生线程,然后再调用CPU,python2这个时候有个问题,为了实现多线程并行效果(cpu的上下文切换),它有一个ticke计数,只要达到100后释放,或者这个时候有IO操作,就会切换到下一个线程。但是这里我有个问题,如果就是同时开两个线程的话,就是两个线程的同时切换,如果我开了5个线程,第一个线程切换的时候,其它4个线程要申请GIL锁才能执行操作,但是这个GIL锁给谁呢?这个时候就会出现一个竞争,会消耗资源(别忘了,python通一个时间值有一下事件再执行),这个就是python在多核CPU上的利用率并没有那么优秀。

   python3的不在使用ticke计数器,而是用计时器,这样的话对CPU密集运算的操作有所提升,但同一时间那还不是只有一个线程在工作(还是利用cpu的上下文切换,实现的并行效果,只是你没看出来而已)。

这么说多线程就真是鸡肋了么?

  CPU密集运算的环境下,即使开的线程再多(不是说线程越多越快,这个数量要适量),我们都知道了python在同一时刻只有一个线程在工作,一个进程只有一个GIL锁,所以不管再多的线程,同一时间就一个线程在工作,对于CPU运算的环境下,意义不大,有点单线程的样子。

  但是对于IO操作密集的环境话(比如数据的持久化操作),效果就会好很多。比如线程A,干完CPU运算的时候去写入文件或者数据库的时候,获取爬虫去请求的时候,这个时候就切换到线程B,这样的话多线程的效率还是较高的。

那相比之下怎么提高效率呢?

  我们知道线程存在于进程内,也就微进程。每个进程里面看有一个GIL锁,开启一个进程的话需要开通内存空间(俗称占内存),但是开线程的话,它是存在于进程内的,所以如果开10个进程和开10线程的话,线程占用的内存空间更小。可是多线程效率并没有那个高啊,怎么办,有人说,我内存你大,我开进程,开10个进程,进程里面有个自己的GIL锁,这样的话,不就等于并行了么,对的,可以整。