存在于Cpython的问题,不同线程去修改同一份数据,就会出现数据不一致的情况,以后pypy是未来,不存在这样的问题。
线程锁(互斥锁Mutex)
一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,每个线程在要修改同一份数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。
在python2中需要自己写,在python3中不需要关注,互斥锁Mutex实例:
# -*- coding:utf-8 -*- # Author:Brownyangyang import threading import time number = 0 lock = threading.Lock() #生成一个锁的实例 class MyThreat(threading.Thread): def __init__(self,n): super(MyThreat, self).__init__() self.n = n def run(self): lock.acquire() #加锁 global number number += 1 #time.sleep(1) #可以在这里加个sleep来验证确实锁生效了 lock.release() #解锁 #这样保证在修改number值的时候线程是串行的 res_list = [] for i in range(5): t = MyThreat(i) t.start() res_list.append(t) for i in res_list: i.join() ##循环任务列表,等待任务结束 print("number的值是",number)
递归锁(大锁中包含了子锁):
# -*- coding:utf-8 -*- # Author:Brownyangyang import threading, time 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) if __name__ == '__main__': num, num2 = 0, 0 lock = threading.RLock ( ) ##递归锁RLock(),如果这里是Lock()就会死循环,因为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)
信号量(Semaphore)
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
# -*- coding:utf-8 -*- # Author:Brownyangyang import threading, time def run(n): semaphore.acquire ( ) ##加锁 time.sleep (1) print ("run the thread: %s " % n) semaphore.release ( ) ##释放锁 if __name__ == '__main__': semaphore = threading.BoundedSemaphore (3) # 生成锁实例,最多允许5个线程同时运行 for i in range (10): t = threading.Thread (target=run, args=(i,)) t.start ( ) while threading.active_count ( ) != 1: pass # print threading.active_count() else: print ('----all threads done---') #可以看到执行效果是3个一打印直到10个任务结束,但是并非是3个执行完一起返回再添加3个,而是完成1个加1个