python中的多线程和GIL

GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行。

在刚了解python中的GIL时,很多小伙伴应该和我一样,不明白既然GIL为进程上了一把锁,使进程内的其他线程无法运行,python中为什么还有多线程的概念?还有在多线程中再加锁?

其实,在python中,并不是等待一个线程结束之后再执行另外一个线程。举个例子,两个线程分别对一个全局变量total进行加和减。

total = 0
def add(name):
    global total
    for i in range(100):
        total += 1
        print('当前是%s线程,i的值为%s' % (name,total))

def desc(name):
    global total
    for i in range(100):
        total -= 1
        print('当前是%s线程,i的值为%s' % (name,total))

import threading
thread1 = threading.Thread(target=add,args=('thread1',))
thread2 = threading.Thread(target=desc,args=('thread2',))

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print(total)

结果是
python中的多线程和GIL_第1张图片
从输出中我们可以看到,并不是等thread1线程执行完再执行thread2线程任务的。

在GIL中,全局所并不是一直锁定的,在线程进行耗时的操作的时候,能会释放GIL。

在CPU密集操作线程中,python的多线程并不会达到并发的效果,不如使用多进程。这里直接借用的一张测试结果图(见下图)。图中表示的是两个线程在双核CPU上得执行情况。两个线程均为CPU密集型运算线程。绿色部分表示该线程在运行,且在执行有用的计算,红色部分为线程被调度唤醒,但是无法获取GIL导致无法进行有效运算等待的时间。由图可见,GIL的存在导致多线程无法很好的立即多核CPU的并发处理能力。
在这里插入图片描述

在IO密集操作线程中,python的多线程还是很快的。比如在网络通信,time.sleep()延时的时候。举个例子,在多线程中,让每个线程休眠10秒。

def sleep_1():
# 休眠10for _ in range(100):
        time.sleep(0.1)

def test_thread():
    time1 = time.time()
    t1 = threading.Thread(target=sleep_1)
    t2 = threading.Thread(target=sleep_1)
    t3 = threading.Thread(target=sleep_1)
    t4 = threading.Thread(target=sleep_1)
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    
    time2 = time.time()
    print("所有线程完成,运行时间为",time2-time1)
if __name__ == '__main__':
    test_thread()

结果为
python中的多线程和GIL_第2张图片

总结:

  1. Python中一个线程并不会从头到尾占用GIL。当一个线程遇到I/O任务时,将释放GIL。计算密集型(CPU-bound)的线程在执行大约100次解释器的计步(ticks)时,将释放GIL。
  2. 在CPU密集操作线程中,python的多线程并不会达到并发的效果,不如使用多进程。比如处理计算的时候。
  3. 在IO密集操作线程中,python的多线程还是很快的。比如在网络通信,time.sleep()延时的时候。

参考:
Python的GIL是什么鬼,多线程性能究竟如何
[python] GIL全局解释器锁

你可能感兴趣的:(多线程,python,thread)