python的GIL(global interpreter lock)全局解释器锁是存在原始解释器Cpython中的,在解释执行python代码时,该互斥锁会限制现成对共享资源的访问,直到解释器遇到I/O操作或者操作次数达到一定数目才会释放GIL。因此在进行多线程操作时,不能调用多个cpu内核,只能利用一个内核,在cpu密集型操作的时候,不推荐使用多线程,跟家倾向于多进程,每个进程都有一个单独的GIL。
多线程在I/O密集型操作时,因为效率的瓶颈在I/O操作,多线程可以明显的提高效率。在开发爬虫时,大多数时间在等待socket返回数据,网络IO操作延时比CPU大的多。
如果没有GIL
如果没有GIL,虽然多线程程序的多核CPU的计算能力利用率会得到提高,但是会导致数据一致性等问题:
1 原子性问题:多个线程同时对同一个变量进行更新,很可能导致数据不一致的问题。
2 竞争条件问题:如果多个线程同时对共享资源进行操作,很可能会出现竞争条件,导致程序的不正确性,如死锁等。
3 同步问题:如果多个线程需要协调合作完成某项任务,就需要进行同步操作,保证多个线程的执行顺序,必须对每一个线程的操作充分考虑。
GIL的取舍
因此GIL在一定程度上会影响到程序的多核CPU利用率,虽然在程序中创建了多线程,但是实际上程序在CPU上依然是串行的,这将导致并发性能降低。
除了使用多进程,如multiprocessing模块来创建多进程,释放多核CPU的性能外。还可以使用异步编程,如gevent、asyncio、Trio等。使用事件循环和协程来实现非阻塞的异步I/O编程。
此外,可以使用C语言等其他语言编写多线程程序,与python交互使用。