python 线程(其他方法,队列,线程池,协程 greenlet模块 gevent模块)
1.线程的其他方法
from threading import Thread,current_thread import time import threading def f1(n): time.sleep(1) print('子线程名称',current_thread().getName())#获取线程名 if __name__=='__main__': t1=Thread(target=f1,args=(1,)) t1.start() print('主线程名称',current_thread().getName()) print('主进程id',current_thread().ident) print(current_thread())#当前线程的对象 print(threading.enumerate())#当前正在运行的线程的一个列表 print(threading.active_count())#当前正在运行的线程的数量 #########结果######## 主线程名称 MainThread 主进程id 7512 <_MainThread(MainThread, started 7512)> [<_MainThread(MainThread, started 7512)>, <Thread(Thread-1, started 5680)>] 2 子线程名称 Thread-1
2.线程队列
import queue ###先进先出 q=queue.Queue(3) q.put(1) q.put(2) print('当前队列内容长度',q.qsize()) q.put(3) print('查看队列是否满了',q.full()) print(q.get()) print(q.get()) print('查看队列是否为空',q.empty()) print(q.get())#在多打一个get会形成程序阻塞 print('查看队列是否为空',q.empty()) try: q.get_nowait()#报错queue.Empty except Exception: print('队列空了') ############################ 当前队列内容长度 2 查看队列是否满了 True 1 2 查看队列是否为空 False 3 查看队列是否为空 True 队列空了
####先进后出 类似于栈 import queue q = queue.LifoQueue(3) # q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) print(q.get()) ############## 3 2 1
####优先级队列 import queue q=queue.PriorityQueue(5) q.put((5,'alex')) q.put((2,'宝宝')) q.put((4,'大力')) print(q.get()) print(q.get()) print(q.get()) ########## (2, '宝宝') (4, '大力') (5, 'alex') #如果优先级数字相同,如果数据类型不同会报错,类型相同会对比元祖中的第二行英语字母
3.线程池
map方法
import time from concurrent.futures import ThreadPoolExecutor from threading import current_thread def func(n): time.sleep(1) print(n) # print(n,current_thread().ident) if __name__ == '__main__': t_p = ThreadPoolExecutor(4) map_res = t_p.map(func,range(10)) #异步执行的,map自带join功能 print(map_res) print([i for i in map_res]) ####################### <generator object Executor.map.<locals>.result_iterator at 0x00000000029E94F8> 012 3 4 5 6 7 89 [None, None, None, None, None, None, None, None, None, None]#会取不到值
concurrent.futures 写法
import time from threading import current_thread from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def func(n): time.sleep(0.1)#此处等待一秒是为了将取值时候的打印结果进行区分 # print(n) return n if __name__ == '__main__': t_p = ThreadPoolExecutor(4)#可以进行线程进程切换 # t_p=ProcessPoolExecutor(4) t_res_lst = [] for i in range(10): res_obj =t_p.submit(func,i) #提交执行函数,返回一个结果对象,i作为任务函数的参数 t_res_lst.append(res_obj) t_p.shutdown() #起到原来的close阻止新任务进来 + join的作用,等待所有的线程执行完毕 # print("t_res_lst",t_res_lst) #<Future at 0x1fa10a43400 state=finished returned int> 加了shutdown后全部变为finished #<Future at 0x19d37f5c7f0 state=running>, <Future at 0x19d37f5c9b0 state=pending>不加shutdo时 for e_res in t_res_lst: print(e_res.result()) # t_p.shutdown() #在不加shutdown时,主线程在循环列表时,也是每一个进行取值, # 但是由于可以有四个对象可以一起取值,(拿前四个为例,) # 也就是当列表循环到4个时此时会等待将近1s # 因为在执行函数有停留,但线程池可以四个同时执行,因此会有4个结果一起出来 #但是当加了shutdown时,此时线程会全部执行完毕,然后在列表里是,此时的对象已经全部执行完毕 ######################## 0 1 2 3 4 5 6 7 8 9
4.协程
协程本质上就是一个线程,以前线程任务的切换是由操作系统控制的,遇到I/O自动切换,在我们自己的程序里面来控制任务的切换。
现在我们用协程的目的就是较少操作系统切换的开销(开关线程,创建寄存器、堆栈等,在他们之间进行切换等),
import gevent from gevent import monkey;monkey.patch_all()#本身不认识其他模块中的IO操作,但是如果我们在导入其他模块之前执行 就能够认识 import time
def f1(): print('第一次f1') # print(threading.current_thread().getName()) # gevent.sleep(1) time.sleep(2) print('第二次f1') def f2(): # print(threading.current_thread().getName()) print('第一次f2') # gevent.sleep(2) time.sleep(2) print('第二次f2') s = time.time() g1 = gevent.spawn(f1) #异步提交了f1任务 g2 = gevent.spawn(f2) #异步提交了f2任务 # g1.join() # g2.join() gevent.joinall([g1,g2]) e = time.time() print('执行时间:',e-s) print('主程序任务') ####################### 第一次f1 第一次f2 第二次f1 第二次f2 执行时间: 2.0021142959594727 主程序任务
下面是理解 :可看 可不看
#####生成器写法 import time def f1(): for i in range(2): time.sleep(0.5) print('f1>>',i) yield def f2(): g = f1() for i in range(2): time.sleep(0.5) print('f2>>', i) next(g) f1() f2() ############ f2>> 0 f1>> 0 f2>> 1 f1>> 1
#######greenlet模块 import time from greenlet import greenlet def f1(s): print('第一次f1'+s) g2.switch('taibai') #切换到g2这个对象的任务去执行 time.sleep(1) print('第二次f1'+s) g2.switch() def f2(s): print('第一次f2'+s) g1.switch() time.sleep(1) print('第二次f2'+s) g1 = greenlet(f1) #实例化一个greenlet对象,并将任务名称作为参数参进去 g2 = greenlet(f2) g1.switch('alex') #执行g1对象里面的任务 ########### #首先会执行g1的switch(alex)也就是执行f1 print('第一次f1'+alex) #往下就会执行f2 进行传参taibai 会打印 第一次f2taibai #往下 执行了g1也就是f1 print('第二次f1'+s) #往下继续走 print('第二次f2'+taibai) ##########结果 第一次f1alex 第一次f2taibai 第二次f1alex 第二次f2taibai
回调函数
#######回调函数 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def f1(n,s): return n+s def f2(n): print('回调函数>>',n.result()) if __name__ == '__main__': tp=ThreadPoolExecutor(4) res=tp.submit(f1,11,12).add_done_callback(f2) ##################### 回调函数>> 23
不怕大牛比自己牛,就怕大牛比自己更努力