一.死锁现象与递归锁
锁:Lock线程安全,多线程操作时,内部会让所有线程排队处理。如:list/dict/Queue
线程不安全 + 人 => 排队处理。
importthreadingimporttime
v=[]
lock=threading.Lock()deffunc(arg):
lock.acquire()
v.append(arg)
time.sleep(0.01)
m= v[-1]print(arg,m)
lock.release()for i in range(10):
t=threading.Thread(target=func,args=(i,))
t.start()
锁:RLock
importthreadingimporttime
v=[]
lock=threading.RLock()deffunc(arg):
lock.acquire()
lock.acquire()
v.append(arg)
time.sleep(0.01)
m= v[-1]print(arg,m)
lock.release()
lock.release()for i in range(10):
t=threading.Thread(target=func,args=(i,))
t.start()
锁:BoundedSemaphore
importtimeimportthreading
lock= threading.BoundedSemaphore(3)deffunc(arg):
lock.acquire()print(arg)
time.sleep(1)
lock.release()for i in range(20):
t=threading.Thread(target=func,args=(i,))
t.start()
锁:condition
importtimeimportthreading
lock=threading.Condition()############### 方式一 ##############
deffunc(arg):print('线程进来了')
lock.acquire()
lock.wait()#加锁
print(arg)
time.sleep(1)
lock.release()for i in range(10):
t=threading.Thread(target=func,args=(i,))
t.start()whileTrue:
inp= int(input('>>>'))
lock.acquire()
lock.notify(inp)
lock.release()############### 方式二 ##############
"""def xxxx():
print('来执行函数了')
input(">>>")
# ct = threading.current_thread() # 获取当前线程
# ct.getName()
return True
def func(arg):
print('线程进来了')
lock.wait_for(xxxx)
print(arg)
time.sleep(1)
for i in range(10):
t =threading.Thread(target=func,args=(i,))
t.start()"""
锁:Event
importtimeimportthreading
lock=threading.Event()deffunc(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 的作用及原理
作用:内部自动为每个线程维护一个空间(字典),用于存取属于自己的值.保证线程之间的数据隔离.
importtimeimportthreading
v=threading.local()deffunc(arg):#内部会为当前线程创建一个空间用于存储:phone=自己的值
v.phone =arg
time.sleep(2)print(v.phone,arg) #去当前线程自己空间取值
for i in range(10):
t=threading.Thread(target=func,args=(i,))
t.start()
原理:
#原理1
importtimeimportthreading
DATA_DICT={}deffunc(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()#原理2
importtimeimportthreading
INFO={}classLocal(object):def __getattr__(self, item):
ident=threading.get_ident()returnINFO[ident][item]def __setattr__(self, key, value):
ident=threading.get_ident()if ident inINFO:
INFO[ident][key]=valueelse:
INFO[ident]={key:value}
obj=Local()deffunc(arg):
obj.phone= arg #调用对象的 __setattr__方法(“phone”,1)
time.sleep(2)print(obj.phone,arg)for i in range(10):
t=threading.Thread(target=func,args=(i,))
t.start()
三.线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
from concurrent.futures importThreadPoolExecutorimporttimedeftask(a1,a2):
time.sleep(2)print(a1,a2)#创建了一个线程池(最多5个线程)
pool = ThreadPoolExecutor(5)for i in range(40):#去线程池中申请一个线程,让线程执行task函数。
pool.submit(task,i,8)
四.生产者消费者模型
产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者;生产者和消费者之间的中介就叫做缓冲区。
importtimeimportqueueimportthreading
q= queue.Queue() #线程安全
defproducer(id):"""生产者
:return:"""
whileTrue:
time.sleep(2)
q.put('包子')print('厨师%s 生产了一个包子' %id )for i in range(1,4):
t= threading.Thread(target=producer,args=(i,))
t.start()defconsumer(id):"""消费者
:return:"""
whileTrue:
time.sleep(1)
v1=q.get()print('顾客 %s 吃了一个包子' %id)for i in range(1,3):
t= threading.Thread(target=consumer,args=(i,))
t.start()