多线程
1、join daemon
join :挂起主线程,待当前线程结束之后,再继续执行挂起主线程(可以指定挂起时间)
daemon:设置守护线程 (setDaemon(True))
默认情况setDaemon(False)
1)当我们使用setDaemon(True)方法,设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行,可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止。
2)join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止。
join有一个timeout参数:当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。
所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。
注意:请确保setDaemon()在start()之前。
import threading,time
def run():
for i in range(100):
time.sleep(0.1)
print("子线程结束")
t1 = threading.Thread(target=run)
t1.setDaemon(True)
t1.start()
print("主线程结束")
import threading,time
def run():
for i in range(100):
time.sleep(0.1)
print("子线程结束")
t1 = threading.Thread(target=run)
t1.setDaemon(True)
t1.start()
t1.join(timeout=5)
print("主线程结束")
2、死锁和可重入锁(递归锁) RLock
可重复锁,是线程相关的锁。使用RLock可重入锁,第一个锁没有释放,第二个也能获取到锁。但只要多一个release就会抛RuntimeError异常,提示无法释放一个un-acquire的锁。
import threading,time
rlock1 = threading.RLock()
rlock2 = threading.RLock()
rlock3 = threading.RLock()
rlock4 = threading.RLock()
rlock5 = threading.RLock()
class ZheXueJia():
def __init__(self,left,right):
self.left = left
self.right = right
z1 = ZheXueJia(rlock5,rlock1)
z2 = ZheXueJia(rlock1,rlock2)
z3 = ZheXueJia(rlock2,rlock3)
z4 = ZheXueJia(rlock3,rlock4)
z5 = ZheXueJia(rlock4,rlock5)
def run(z,name):
f = z.left.acquire()
if f:
print(name,"获取左筷子")
ff = z.right.acquire()
if ff:
print(name, "获取右筷子")
print("哲学家开始就餐",name)
time.sleep(1)
z.right.release()
z.left.release()
t1 = threading.Thread(target=run,args=(z1,"t1"))
t2 = threading.Thread(target=run,args=(z2,"t2"))
t3 = threading.Thread(target=run,args=(z3,"t3"))
t4 = threading.Thread(target=run,args=(z4,"t4"))
t5 = threading.Thread(target=run,args=(z5,"t5"))
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
3、信号量Semaphore
信号量Semaphore本质也是一把锁,但是这把锁可以限定允许多个任务同时执行任务,
但是不能超出规定的限制。
import threading,time
s = threading.Semaphore(3)
def run(name):
s.acquire()
print(name,"开始执行")
time.sleep(1)
print(name,"执行结束")
s.release()
start_time = time.time()
t1 = threading.Thread(target=run,args=("t1",))
t2 = threading.Thread(target=run,args=("t2",))
t3 = threading.Thread(target=run,args=("t3",))
t4 = threading.Thread(target=run,args=("t4",))
t5 = threading.Thread(target=run,args=("t5",))
t6 = threading.Thread(target=run,args=("t6",))
t7 = threading.Thread(target=run,args=("t7",))
t8 = threading.Thread(target=run,args=("t8",))
t9 = threading.Thread(target=run,args=("t9",))
t10 = threading.Thread(target=run,args=("t10",))
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
t6.start()
t7.start()
t8.start()
t9.start()
t10.start()
t1.join()
t2.join()
t3.join()
t4.join()
t5.join()
t6.join()
t7.join()
t8.join()
t9.join()
t10.join()
end_time = time.time()
print(end_time-start_time)
4、定时器(一种特殊的线程)
注意传参时必须是元组形式
threading.Timer()
import threading
def deal_task(n):
print("%s 我被执行了"%n)
t = threading.Timer(3,deal_task,args=(10,))
t.start()
5、事件 Event
首先创建10个线程代表10辆车正在等信号灯,创建1个线程代表信号灯,当10辆汽车被创建后就等着信号灯发信号起跑,当遇到e.wait()时程序被挂起,等待信号灯变绿,而e.set()就是来改变这个状态让信号灯变绿,当e.set被设置后cars等到了信号,就可以继续往后跑了,代码可以继续执行了。e.set()默认False,e.set()调用后值变为True,e.wait()接收到后程序由挂起变为可执行。
import threading,time
e = threading.Event()
def hld():
print("现在是红灯")
time.sleep(5)
e.set()
print("现在是绿灯")
def car_run(name):
print(name,"迎面驶来")
e.wait()
print(name,"继续前行")
for i in range(10):
t = threading.Thread(target=car_run,args=(i,))
t.start()
h = threading.Thread(target=hld)
h.start()
6、线程队列
队列Queue: queue.Queue()
堆栈Queue: queue.LifoQueue()
优先级Queue: queue.PriorityQueue()
1)队列Queue
import queue
q = queue.Queue()
q.put('1')
q.put(1)
q.put({'a': 1})
print(q.get())
print(q.get())
print(q.get())
先进先出
可以存放任意类型数据
2)堆栈Queue
import queue
q = queue.LifoQueue()
q.put(1)
q.put('1')
q.put({'a': 1})
print(q.get())
print(q.get())
print(q.get())
可以存放任意数据类型
Lifo代表后进先出
3)优先级Queue
import queue
q = queue.PriorityQueue()
q.put((10, 'Q'))
q.put((30, 'Z'))
q.put((20, 'A'))
print(q.get())
print(q.get())
print(q.get())
存放的数据是元组类型,带有优先级数字越小优先级越高。
数据优先级高的优先被取出。
用于VIP用户数据优先被取出场景,因为上面两种都要挨个取出。