GIL锁(Global Interpreter Lock):CPython才会有(是这种解释器的历史遗留问题),Python程序执行前,先获得GIL锁,然后每执行100个指令,解释器就自动释放GIL锁,让别的线程执行。所以,多线程在Python中只能交替执行,同一时间只有一个线程在执行。
Python多线程一般应用于IO密集型程序,不适合用于CPU密集型(以计算为主)程序,因为线程之间的上下文切换也需要时间。如下面例子,多线程不如单线程效率高:
两线程串行:
#coding=utf-8 import threading import time def computed(): i = 0 for n in xrange(100000000): i += 1 thread_list = [] for _ in range(2): time_begin = time.time() thread_list.append(threading.Thread(target=computed)) thread_list[_].start() thread_list[_].join() print '两线程串行总运行时间:{}'.format(time.time() - time_begin) # 两线程串行总运行时间:3.20499992371
两线程并行
#coding=utf-8 import threading import time def computed(): i = 0 for n in xrange(100000000): i += 1 thread_list = [] for _ in range(2): time_begin = time.time() thread_list.append(threading.Thread(target=computed)) thread_list[_].start() for t in range(2): thread_list[t].join() print '两线程并行总运行时间:{}'.format(time.time() - time_begin) # 两线程并行总运行时间:23.4430000782
线程锁是什么?为什么有了GIL锁还需要线程锁?
在多线程的运算中,可能一个线程执行了100个指令,在切换到了另一个线程的时候,由于它没有计算完毕,而且另一个线程也操作同一个内存对象,这样很容易出现混乱。
说具体点儿,比如一个线程把内存中的a,加1加到一半,切换到另一个线程,另一个线程也是对a加1,且已经加完,并把结果赋给了内存中的a(可以理解为另一个线程的操作不需要这么多指令?),然后第一个线程还是把之前a的值加1,并不是从内存中重新读取再加,所以第一个线程加完之后把结果赋给内存,这样就相当于另一个线程没加上。为了避免这样的问题出现,所以使用线程锁。
#coding=utf-8 import threading import time n, thread_list = 0, [] def computed(): global n n += 1 for _ in xrange(10000): thread_list.append(threading.Thread(target=computed)) thread_list[_].start() for t in thread_list: t.join() print n
递归锁
#coding=utf-8 import threading def run1(): print 'grab the first part data' lock.acquire() global num num += 1 lock.release() return num def run2(): print 'grab the second part data' lock.acquire() global num2 num2 += 1 lock.release() return num2 def run3(): lock.acquire() res = run1() print '-------between run1 and run2------' res2 = run2() lock.release() print res, res2 num, num2 = 0, 0 lock = threading.Lock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: print threading.active_count() else: print '---all threads done---' print num, num2
感觉就是锁的嵌套,结果会不停返回“11”,出现混乱。解决方案用递归锁threading.Rlock()。