threading模块:利用CPU空闲时间执行多任务。Python的多线程实际是遇到IO操作就CPU切换到其它任务。
1、GIL (Global Interpreter Lock):全局解释器锁
2、简单的threading使用
常用类和方法名: | 参数 | 作用 | 示例 |
threading.enumerate() | 用列表,列出所有活动的线程名和ID 示例中列出的是 |
s = threading.enumerate() for v in s: print(v.name) |
|
threading.Tread.isAlive(线程实例名) |
线程实例名:下面的thread_create | 判断线程是否正在运行,返回True或False | threading.Tread.isAlive(ss) 或者 i.isAlive() #i是创建的Thread实例 |
thread_create=threading.Thread() |
target:加入多线程的对象名 args:对象的参数,元组形式 kwargs:对象的字典参数 name:指定线程名,默认Thread-N |
把一个对象实例化成一个线程对象 |
thread_create = threading.Tread(target=work,args=('tom',),kwargs={'work_name':'eat'}) |
thread_create.start() | 启动线程 | thread_create.start() | |
thread_create.join() | timeout:线程阻塞的时间(超时时间) timeout默认,等待此线程执行完毕 |
等待至线程中止或timeout超时,再继续执行程序
|
thread_create.join(5) 或者 thread_create.join(timeout=5) |
thread_create.getName() | 获取thread_create线程名 | thread_create.getName() | |
thread_create.setName() | name:线程名 | 设置thread_create线程名,这个名字只是标识 | thread_create.setName('th1') |
""" 简单的例子 可以使用两种方法创建多线程 """ #方法一:函数式调用。 import time,random import threading work_list = ["睡觉" ,"吃饭", "学习" ,"嗯哼"] # 工作列表 def work(name, cost): '''定义函数''' print(" 你开始 [31;2m{}[0m".format(name)) time.sleep(cost) print("{} 竟然只用了{}秒钟!".format(name, cost)) thread_list = [] # 线程列表 start_time = time.time() # 记录开始的时间 # 线程开始 for i in work_list: #循环读取工作内容 cost_time= random.randint(5,10) # 生成随机时间,传输给函数 # 创建多线程实例 t = threading.Thread(target = work,args=(i,cost_time)) thread_list.append(t) # 把实例内存地址存储到列表,后续使用 t.start() # 开启线程 active_thread = threading.enumerate() #列出当前所有活动的线程 print(active_thread) #结果是一个列表 for i in active_thread: print (i.name) # 调用线程的name属性,表出线程名,实际是调用Thread类析构函数的self.name属性,在方法二里面会看到线程名和工作名是一样的 print(i.getName()) # 获取当前线程名称 i.setName("change-name"+i.name) #改名 print(i.getName()) # 重新获取线程名字 for i in thread_list: # 从列表里读取线程地址 i.join() # 每个线程加入阻塞,默认值等每个线程都结束,继续运行 end_time = time.time() # 记录结束的时间 sum_time = end_time - start_time # 计算总耗时 print ('总用时:{}'.format(sum_time))
'''方法二:重构Thread类的run函数,请注意,只能重构__init__和run函数,其它的不要重构!!!!!''' import time,random import threading '''重写run方法调用''' work_list = ["睡觉" ,"吃饭", "学习" ,"嗯哼"] # 工作列表 class work(threading.Thread): def __init__(self,name,cost): threading.Thread.__init__(self) self.name = name self.cost = cost def run(self): self.do_work() def do_work(self): """工作函数""" print(" 你开始 [31;2m{}[0m".format(self.name)) time.sleep(self.cost) print("{} 竟然只用了{}秒钟!".format(self.name, self.cost)) start_time = time.time() # 记录开始的时间 thread_list = [] for i in work_list: cost_time = random.randint(5,9) t = work(i, cost_time) thread_list.append(t) t.start() active_thread = threading.enumerate() for i in active_thread: print(i.name) # 打印出来的是工作名称,不是Thread-N这个形式的!!! for i in thread_list: i.join() end_time = time.time() # 记录结束的时间 sum_time = end_time - start_time # 计算总耗时 print ('总用时:{}'.format(sum_time))
3、守护线程deamon
类、方法、属性名 |
参数 | 作用 | 示例 |
setDaemon(BOOL) |
BOOL:True False |
设置线程为父线程的守护线程,必须在strar()线程开始前设置。 |
m为创建的进程实例。 m.setDaemon(True) |
isDaemon() |
无 |
判断当前线程是否设置了守护线程 返回BOOL型,True 或 False |
m.isDaemon() |
"""守护线程Daemon实例""" import time,random import threading work_list = ["睡觉" ,"吃饭", "学习" ,"嗯哼"] # 工作列表 def work(name, cost): '''定义函数''' print(" 你开始 [31;2m{}[0m".format(name)) time.sleep(cost) print("{} 竟然只用了{}秒钟!".format(name, cost)) def main_work(name): w = threading.Thread(target = work, args=("嗯哼",10)) w.start() w.join(9) start_time = time.time() # 记录开始的时间 m = threading.Thread(target = main_work, args=('Done',)) m.setDaemon(True) # 设置守护进程,主线程完成,main_work结束,main_work的子线程也结束 m.start() m.join(2) end_time = time.time() print("你{}了!!!".format("Done")) print ("总耗时:",end_time-start_time) #-------------执行结果-------------- 你开始 [31;2m嗯哼[0m 你Done了!!! 总耗时: 2.0008544921875 #--因为设置m为守护线程,所以当主线程执行结束后,m和由m生成的所有线程都随着主线程结束。
4 、线程锁Lock、递归锁Rlock
加锁以后线程依次运行。
类、方法、属性名 | 参数 | 作用 | 示例 |
Lock() |
Lock类,用于创建Lock对象 |
lock = threading.Lock() |
|
Rlock() |
Rlock类,用于创建递归锁,也叫做多重锁 同一线程可以acquire()多次,但要对应相同数量的release() |
rlock = threading.Rlock() |
|
acquire() |
Lock和Rlock的方法: 启用线程锁 |
lock.acquire() |
|
release() |
Lock和Rlock的方法: 释放线程锁 |
lock.release() |
|
###Lock实例### import time,random import threading work_list = ["睡觉" ,"吃饭", "学习" ,"嗯哼"] # 工作列表 def work(name,cost): '''定义函数''' lock.acquire() #线程锁启用 work_list[name] = name time.sleep(cost) print("time:{},list:{}".format(cost,work_list)) lock.release() #线程锁释放,只有释放后,才能运行其它线程 start_time = time.time() # 记录开始的时间 thread_list = [] lock = threading.Lock() for i in range(3): m = threading.Thread(target = work, args=(i,3)) thread_list.append(m) m.start() for i in thread_list: i.join() end_time = time.time() print ("总耗时:",end_time-start_time) -----------------加锁版运行结果------------------ time:3,list:[0, '吃饭', '学习', '嗯哼'] time:3,list:[0, 1, '学习', '嗯哼'] time:3,list:[0, 1, 2, '嗯哼'] 总耗时: 9.002515077590942 -----------------不加锁运行结果------------------ time:3,list:[0, 1, 2, '嗯哼'] time:3,list:[0, 1, 2, '嗯哼'] time:3,list:[0, 1, 2, '嗯哼'] 总耗时: 3.002171516418457
5 、信号量(semaphore)
类、方法、属性名 | 参数 | 作用 | 示例 |
BoundedSemaphore(num) | num:int型,只允许num个线程同时运行 | 创建一个semaphore对象 | semaphore = threading.BoundedSemaphore(3) |
acquire() | 把线程加入信号量对象 | semaphore .acquire() | |
release() | 把线程从信号量对象中删除 | semaphore .release() | |
待测试 import threading,time,random work_list = ["睡觉" ,"吃饭", "学习" ,"嗯哼"] # 工作列表 def work(name,cost): semaphore.acquire() print("{}用了{}分钟".format(name,cost)) time.sleep(cost) #print(name) semaphore.release() thread_list=[] semaphore = threading.BoundedSemaphore(3) index = "" for i in work_list: index = index+str(work_list.index(i)) num = random.randint(2,5) t = threading.Thread(target=work, args = (i+index,num)) thread_list.append(t) t.start() for j in thread_list: j.join() print ("Done") #------------结果------------ 睡觉0用了2分钟 吃饭01用了5分钟 学习012用了4分钟 #以上三个先出现,下面一行后出现,说明了一次只能运行三个线程 嗯哼0123用了2分钟
5 、定时器(Timer)
类、方法、属性名 | 参数 | 作用 | 示例 |
Timer(time,func,args) |
time:延时时间(单位:秒) func:要执行的函数名 args:参数,与多进程使用方法一样 |
生成定时器实例,过time的时长后,执行func的功能。 |
timer=threading.Timer(3,work,('David',)) |
start() |
启动定时器 |
timer.start() | |
stop() |
停止定时器 |
timer.stop() | |
import threading def work(name): print ("循环:{}".format(name)) global timer timer=threading.Timer(3,work,('David',)) timer.start() timer=threading.Timer(3,work,('David',)) timer.start()
6 、事件(Event)
Event是线程同步的一种方式,类似于一个标志,当该标志为false时,所有等待该标志的线程阻塞,当为true时,所有等待该标志的线程被唤醒。
Event是一个重要的概念,有一个编程思想叫事件驱动模型。稍后讨论。
类、方法、属性名 | 参数 | 作用 | 示例 |
Event() |
无 |
实例化事件对象 |
e = threading.Event() |
isSet() |
无 |
判断事件标志,返回True或False |
e.isSet() |
set() |
无 |
设置事件标志,isSet()为True |
e.set() |
clear() |
无 |
清除事件标志,isSet()为True | e.clear() |
wait(timeout) |
timeout:时间 |
####事件驱动的红绿灯实例#### import threading import time class traffic(threading.Thread): '''使用继承类方式写一个进程''' def __init__(self,event_obj): threading.Thread.__init__(self) self.event_obj = event_obj # 传递事件对象 def light(self): sec = 1 # 秒数 while True: if sec / 1 == 1: # 初始绿灯 self.event_obj.set() # 设置事件标志 print ('green...') elif sec / 5 == 1: # 计数5秒,变黄灯,黄灯可以通行,所以不改变事件标志 print ('yellow...') elif sec / 7 == 1: # 计数7秒,变红灯 self.event_obj.clear() # 清除事件标志 print('red...') elif sec == 10: # 到10秒重新计数 sec = 1 continue sec += 1 time.sleep(1) # 延迟 def run(self): # 重写run函数,启动灯。 self.light() def car(event_obj): # 汽车通行函数 while True: if event_obj.isSet(): # 判断事件标志是True,代表绿灯,打印通行 print('the car is running!') else: # 判断事件标志是False,代表红灯,打印通行 print('the car is stop!') time.sleep(1) # 延迟 def exit(): # 定义控制函数,检测鼠标输入,C则结束所有进程,退出程序 t = traffic(e) # 创建信号灯线程对象 c = threading.Thread(target=car, args=(e,)) # 创建汽车线程对象 t.setDaemon(True) # 把两个设置成守护线程,跟随exit结束 c.setDaemon(True) t.start() # 线程启动 c.start() while True: # 循环检测键盘输入 s = input().strip() # 读取键盘输入字符 if s == 'c': # 如果为C,结束exit print('程序退出!') return e = threading.Event() # 创建事件对象 ex=threading.Thread(target=exit) # 创建exit进程对象 ex.start() ex.join()
参考资料:
https://blog.csdn.net/drdairen/article/details/60962439
https://www.cnblogs.com/wang-can/p/3582051.html
https://blog.csdn.net/wanghaoxi3000/article/details/70880753\
https://www.cnblogs.com/nulige/p/6297829.html