1.线程通信:
Event
Event是线程间通信间的机制之一:一个线程发送一个event信号,其他的线程则等待这个信号。常用在一个线程需要根据另外一个线程的状态来确定自己的下一步操作的情况。
Event原理:事件对象管理一个内部标志,通过set()方法将其设置为True,并使用clear()方法将其设置为False。wait()方法阻塞,直到标志为True。该标志初始为False。
Event类提供了如下几个方法:
is_set():当且仅当内部标志为True时返回True。
set():将内部标志设置为True。所有等待它成为True的线程都被唤醒。当标志保持在True的状态时,线程调用wait()是不会阻塞的。
clear():将内部标志重置为False。随后,调用wait()的线程将阻塞,直到另一个线程调用set()将内部标志重新设置为True。
wait(timeout=None):阻塞直到内部标志为真。如果内部标志在wait()方法调用时为True,则立即返回。否则,则阻塞,直到另一个线程调用set()将标志设置为True,或发生超时。该方法总是返回True,除非设置了timeout并发生超时。
创建一个线程,等待你的通知在执行,这就是线程通信。
import threading
import time
def goevent():
e=threading.Event()
def go():
e.wait()#等待
print("go")
threading.Thread(target=go).start()#开启一个线程
return e
t=goevent()
time.sleep(5)
t.set()#激发事件
结果:
等待5秒后就会打印“go”
加强版:
import threading
import time
def goevent():
e=threading.Event()
def go():
for i in range(10):
e.wait()#等待
e.clear()#若不重置,wait第二次不在发挥作用
print(i,"go")
threading.Thread(target=go).start()#开启一个线程
return e
t=goevent()
for i in range(10):
time.sleep(i)
t.set()#通知
结果:
3.condition:
import threading
import time
cond=threading.Condition()
def go1():
with cond:#使用条件变量
for i in range(10):
time.sleep(1)
print(threading.current_thread().name,i)
if i==5:
cond.wait()#等待
def go2():
with cond:#使用条件变量
for i in range(10):
time.sleep(1)
print(threading.current_thread().name, i)
cond.notify()#通知
threading.Thread(target=go1).start()
threading.Thread(target=go2).start()
结果:
Condition
Condition 是一个多线程协调通信的工具类,可以让某些线程一起等待某个条件(condition),只有满足条件时,线程才会被唤醒
condition 中两个最重要的方法,一个是 await,一个是 signal 方法
await:把当前线程阻塞挂起
signal:唤醒阻塞的线程
源码分析
调用 Condition,需要获得 Lock 锁,所以意味着会存在一个 AQS 同步队列,在上面那个案例中,假如两个线程同时运行的话,那么 AQS 的队列可能是下面这种情况,一个线程获得锁,另一个线程进入到同步队列
condition.wait()
Condition
Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。
可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于状态图中的等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。
构造方法:
Condition([lock/rlock])
实例方法:
acquire([timeout])/release(): 调用关联的锁的相应方法。
wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。
notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。
notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常.
4.线程调度:
import threading
import time
cond=threading.Condition()
def go1():
with cond:#使用条件变量
for i in range(0,4):
time.sleep(1)
print(threading.current_thread().name,i)
cond.notify() # 通知
cond.wait()#等待
def go2():
with cond:#使用条件变量
for i in range(3,-1,-1):
time.sleep(1)
print(threading.current_thread().name, i)
cond.wait() # 等待
cond.notify()#通知
threading.Thread(target=go1).start()
threading.Thread(target=go2).start()
结果:
5.生产消费者模式:
import threading
import time
import random
import queue
class Maker(threading.Thread):
def __init__(self,index,myqueue):
threading.Thread.__init__(self)
self.index=index
self.myqueue=myqueue
def run(self):
while True:
time.sleep(3)#三秒生产一个
num=random.randint(1,1000000)#随机数
self.myqueue.put("creat "+str(self.index)+"充气娃娃"+str(num))
print("creat "+str(self.index)+"充气娃娃"+str(num))
self.myqueue.task_done()
class Buyer(threading.Thread):
def __init__(self, index, myqueue):
threading.Thread.__init__(self)
self.index = index
self.myqueue = myqueue
def run(self):
while True:
time.sleep(1)
item=self.myqueue.get()#抓取数据
if item is None:
break
print("客户",self.index,"买到充气娃娃",item)
myqueue=queue.Queue(10)#0代表无限,10代表最大容量为10
for i in range(3):#三个生产者
Maker(i,myqueue).start()
for i in range(8):#8个消费者
Buyer(i,myqueue).start()
结果:
6.线程池:
import threadpool
import time
"""默认不会发生线程冲突"""
def show(str):
print("hello,",str)
time.sleep(2)
namelist=["乔一","唐磊","高泽"]
starttime=time.time()
pool=threadpool.ThreadPool(10)#最大容量十个
request=threadpool.makeRequests(show,namelist)#设置参数
for req in request:#遍历每一个请求,并开始执行
pool.putRequest(req)#压入线程池开始执行
endtime=time.time()
print(endtime-starttime)
结果:
7.定时线程:
8.with用法:
import threading
mutex=threading.Lock()#创建一个锁
num=0
class Mythread(threading.Thread):
def run(self):
global num
with mutex:
for i in range(1000000):#锁定期间其他人不能干活
num+=1
print(num)
mythread=[]
for i in range(5):
t=Mythread()
t.start()
mythread.append(t)
for i in mythread:
t.join()
print("over")
"""
with mutex:
for i in range(1000000):#锁定期间其他人不能干活
num+=1
print(num)
二者等价
if mutex.acquire(1):#锁住成功继续干活,没有成功就一直等待,1代表独占
for i in range(1000000):#锁定期间其他人不能干活
num+=1
mutex.release()#释放锁
"""
结果:
with mutex: for i in range(1000000):#锁定期间其他人不能干活 num+=1 print(num) 二者等价 if mutex.acquire(1):#锁住成功继续干活,没有成功就一直等待,1代表独占 for i in range(1000000):#锁定期间其他人不能干活 num+=1 mutex.release()#释放锁
9.后台线程:
import threading import _thread import win32api class Mythread(threading.Thread):#继承 def run(self):#重写 win32api.MessageBox(0,"你完了","正义的使者",1) mythread=[] for i in range(5): t = Mythread()#创建 t.setDaemon(1) t.start()#开启 mythread.append(t) print("over")
结果:
10.TSL:
import threading
import time
data=threading.local()#每个线程独立存储空间
t1=lambda x:x+1
t2=lambda x:x+"1"
def printdata(func,x):#func是一个函数,x代编参数
data.x=x#data是一个类,动态绑定,线程独立 =1,="1" data.x在每个线程独立
print(id(data.x))#代表不同地址
for i in range(5):
print(threading.current_thread().name,data.x)
data.x=func(data.x)
threading.Thread(target=printdata,args=(t1,1)).start()
threading.Thread(target=printdata,args=(t2,"1")).start()
结果: