几大锁
一 在python里边 列表 字典 队列等都是线程安全的 ,
# v = [] 默认列表是安全的不用加锁 # def func(arg): # v.append(arg) # 线程安全 在一个线程来添加的同时,不会有别的线程来捣乱,
#一个线程添加完毕,别的线程才会紧接着添加
# print(v) # for i in range(10): # t =threading.Thread(target=func,args=(i,)) # t.start()
二 Lock和Rlock
Lock 几乎不用,不能重复获得锁,不能重复解锁.一旦这样做的话,会形成死锁.
Rlock 可以做到上面的重复获得锁,重复解锁
import threading,time a = [] def fun(arg): a.append(arg) 这句代码本身是安全的, time.sleep(0.1) 后面这又要取出列表中的最后一个值,等待一秒之后
#这就线程不安全了.此时10个数都已经被添加进列表,最后取出的当然都是9 print(a[-1]) for i in range(10): t = threading.Thread(target=fun,args=(i,)) t.start() 结果 9 9 9 9 9 9 9 9 9 9 9 9
下面加一把锁,试试看
import threading,time lock = threading.RLock() #赋值给一个变量用着简单 a = [] def fun(arg):
#lock.acquire() #即使加上两把锁,只要后面解两下就和加一次锁解一次锁是一样的 lock.acquire() a.append(arg) time.sleep(0.1) print(a[-1]) lock.release()
# lock.release() for i in range(10): t = threading.Thread(target=fun,args=(i,)) t.start()
结果是 o 1 2 3 4 5 6 7 8 9
semaphore 锁
import time ,threading lock = threading.BoundedSemaphore(2) #里面的参数是一次性最多放行2 个线程 def func(arg): lock.acquire() na = threading.get_ident() time.sleep(2) print(arg,"线程id是%s"%na) lock.release() for i in range(20): t = threading.Thread(target=func,args=(i,)) t.start()
condition锁
import threading lock = threading.Condition() def func(arg): #根据用户动态输入的数据,决定一次性放行线程的个数 lock.acquire() lock.wait() #满足条件就就运行,不满足条件就等着 print(arg) lock.release() for i in range(20): t = threading.Thread(target=func,args=(i,)) t.start() while True: inp = int(input(">>>")) #一定要变成int类型 lock.acquire() lock.notify(inp) lock.release()
event锁(可联想红绿灯)
import time import threading lock = threading.Event() def func(arg): print('线程来了') lock.wait() # 加锁:红灯 print(arg) for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start() input(">>>>") #这里输入东西就可以打开绿灯,进而将 0 1 2 3 4 5 6 7 8 9 依次打印出来 lock.set() # 绿灯
import time import threading lock = threading.Event() def func(arg): print('线程来了') lock.wait() # 加锁:红灯 print(arg) for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start() input(">>>>") lock.set() # 绿灯 # lock.clear() # 再次变红灯 这里如果不加红灯 接下来的十个线程,会同行,所以要在这里再次加上红灯,
然后再次输入任意字符进行放行 for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start() input(">>>>") lock.set()
三 threading.local
import time import threading v = threading.local() def func(arg): # 内部会为当前线程创建一个空间用于存储:phone=自己的值 v.phone = arg # time.sleep(0.1) print(v.phone,arg,"**") # 去当前线程自己空间取值 红色标注的这个是活的 for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start()
#原理
import time import threading DATA_DICT = {} def func(arg): ident = threading.get_ident() DATA_DICT[ident] = arg time.sleep(1) print(DATA_DICT[ident],arg) for i in range(10): t =threading.Thread(target=func,args=(i,)) t.start()
import time import threading INFO = {} class Local(object): def __getattr__(self, item): ident = threading.get_ident() return INFO[ident][item] def __setattr__(self, key, value): ident = threading.get_ident() if ident in INFO: INFO[ident][key] = value else: INFO[ident] = {key:value} obj = Local() def func(arg): obj.phone = arg # 调用对象的类中 __setattr__方法(“phone”,1) time.sleep(2) print(obj.phone,arg) #会自动调用类中__getattr__
for i in range(10):
t =threading.Thread(target=func,args=(i,))
t.start()
四 线程池
from concurrent.futures import ThreadPoolExecutor import time def task(a1,a2): # time.sleep(0.3) print(a1,a2) # 创建了一个线程池(最多5个线程) pool = ThreadPoolExecutor(5) for i in range(6): # 去线程池中申请一个线程,让线程执行task函数。(最多申请到5个,5个以后就会比之前的慢一点,因为只能等之前的线程池执行完毕,才能接着接线程) pool.submit(task,i,8)
四生穿着消费者模型
import time import queue import threading q = queue.Queue() # 线程安全 def producer(id): """ 生产者 :return: """ while True: time.sleep(2) q.put('包子') print('厨师%s 生产了一个包子' %id ) for i in range(1,4): t = threading.Thread(target=producer,args=(i,)) t.start() def consumer(id): """ 消费者 :return: """ while True: time.sleep(1) v1 = q.get() print('顾客 %s 吃了一个包子' % id) for i in range(1,3): t = threading.Thread(target=consumer,args=(i,)) t.start()

浙公网安备 33010602011771号