1、线程的其他方法
Threading.current_thread() # 当前线程对象
getName() 获取线程名
Ident 获取线程id
Threading.Enumerate() # 返回当前正在运行的线程对象的一个列表
Threading.active_count() 当前正在运行的线程数量
例子
先进后出\后进先出队列:queue.LifoQueue(3)
优先级队列:queue.priorityQueue(3)
import threading import time from threading import Thread,current_thread def f1(n): time.sleep(1) print('子线程名称',current_thread().getName()) # Thread-1 print(f"{n}号线程任务") if __name__ == '__main__': t1 = Thread(target=f1,args=(1,)) t1.start() print('主线程的名称:',current_thread().getName()) # MainThread print('主线程的id',current_thread().ident) print(current_thread()) # <_MainThread(MainThread, started 11088)> print(threading.enumerate()) # [<_MainThread(MainThread, started 11088)>, <Thread(Thread-1, started 9176)>] print(threading.active_count())
2、线程队列:(重点)
import queue
先进先出队列:queue.Queue(3)
import queue q = queue.Queue(3) # 先进先出 #fifo first in first out q.put(1) q.put(2) print('当前队列内容长度:',q.qsize()) q.put(3) print('查看队列是否满了:',q.full()) try: q.put_nowait(4) except Exception: print('队列满了') print(q.get()) print(q.get()) print('产看队列是否空:',q.empty()) print(q.get()) try: q.get_nowait() except Exception: print('队列空了')
# 二先进后出,或者后进先出,类似于栈 import queue q = queue.LifoQueue(3) q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) print(q.get())
# 优先级队列 q = queue.PriorityQueue(5) q.put((4,'zhouxiao')) q.put((3,[1,2,3])) q.put((3,[3,4,5])) q.put((8,{'x':44})) q.put((2,(4,7,))) # 如果说值里面的元素是数字类型,那么当两个值的优先级相同时,比较的是两个值的大小,小的优先被取出来 # 如果元素是字符串,那么一次比较字母的ascii表总的位置,小的优先被取出 # 如果优先级数字相同,数据类型不一致会报错 print(q.get()) print(q.get()) print(q.get()) print(q.get()) print(q.get()) print(q.get()) 结果: (2, (4, 7)) (3, [1, 2, 3]) (3, [3, 4, 5]) (4, 'zhouxiao') (8, {'x': 44})
put 的数据是一个元组,元组的第一个参数是优先级数字,数字越小优先级越高,越先被get到被取出来,第二个参数是put进去的值,如果优先级相同,后边的值应该是相同的数据类型
3、线程池:
concurrent.futures 模块提供了高度封装的异步调用接口
ThreadPoolExecutor :线程池,提供异步调用
ProcessPoolExecutor :进程池,提供异步调用
from concurrent_futures import ThreadPoolExecutor,ProcessPoolExecutor
p = ThreadPoolExecutor(4) # 默认的线程个数是cpu个数*5
p = ProcessPoolExecutor(4) # 默认的进程个数是cpu个数
p.map(f1,可迭代对象) # 异步执行
def f1(n1,n2):
print(n1,n2)
p.submit(f1,11,12) # 异步提交任务
res = p.submit(f1,11,12)
res.result() # 和get方法一样,如果没有结果,会等待,阻塞程序
shutdown() # close 和join,锁定线程池,等待线程池中所有已经提交的任务全部执行完成
import time from threading import current_thread from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def f1(n,s): time.sleep(1) print(f"{current_thread().ident}号子线程") # print(n,s) return n*s if __name__ == '__main__': # tp = ThreadPoolExecutor(4) tp = ProcessPoolExecutor(4) # tp.map(f1,range(10)) #异步提交任务,参数同样是任务名称,可迭代对象 res_list =[] for i in range(10): res = tp.submit(f1,i,'xiaoeng') # submit是给线程池异步提交任务 print(res) # res.result() res_list.append(res) for r in res_list: print(r.result()) tp.shutdown() # 主线程等待所有提交给线程池的任务,全部执行完毕,close+join # for r in res_list: # print(r.result()) print('主线程结束')
import time import os import threading from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def func(n): time.sleep(2) print('%s打印的:'%(threading.get_ident()),n) return n*n tp = ThreadPoolExecutor(max_workers = 5) # 默认一般线程的数据不超过cpu个数*5 # tp = ProcessPoolExecutor(max_workers=5) # 进程池的使用只需要将上面的ThresdPoolExecutor 改为ProcessPoolExecutor就行了,其他的不用改 # 异步执行 t_list = [] for i in range(5): t = tp.submit(func,i) # 提交执行函数,返回一个结果对象,i作为任务函数的参数 def submit(self,fn,*args,**kwargs):可以传任意形式的参数 t_list.append(t) print(t.result()) # 这个返回的结果对象t,不能直接去拿结果,不然会又变成串行,可以理解为拿到一个号码,等所有线程的结果都出来之后,我们再去通过结果对象t获取结果 tp.shutdown() # 起到原来的close阻止新任务进来 + join的作用,等待所有线程执行完毕 print('主线程') for t in t_list: print('>>>>',t.result()) # # 也可以不用shutdown()。用下面的这种方式 # while 1: # for n,t in enumerate(t_list): # print('>>>>',t.result()) # time.sleep(2) # 每个两秒去取一次结果,哪个有结果了,就可以取出哪一个,想表达的意思就是说不用等到所有的结果都出来再去取,可以轮着去取结果,因为任务需要执行的时间很长,那么将会等很久才能拿到结果,通过这样的方式可以将快速出来的结果先拿出来,如果有的结果对象里面还没有执行结果,那么将什么也取不到,这一点要注意,不是空的,是什么也取不到,可以通过enumerate来判断我们已经取出了那个结果,记录你是哪一个位置的结果对象的结果已经被取过,取过的就不再取了。 # # # 结果分析:打印的结果是没有顺序的,因为到了func函数中的sleep的时候,线程会切换,谁先打印就没准了,但是最后的我们通过结果对象取结果的时候拿到的是有序的,因为我们主线程进行for循环的时候,我们是按照顺序将结果对象添加到列表中
map的使用
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import threading import os,time,random def task(n): print(f"{threading.get_ident()} is runing") time.sleep(random.randint(1,3)) return n**2 if __name__ == '__main__': executor=ThreadPoolExecutor(max_workers=3) # for i in range(11): # future=executor.submit(task,i) s = executor.map(task,range(1,5)) # map取代了for+submit print([i for i in s])
回调函数简单应用
import os,time import threading from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def func1(n): time.sleep(2) return n*n def func2(m): print('func2结果为:%s'%(m.result())) tp = ThreadPoolExecutor(max_workers=5) t_list = [] for i in range(5): t = tp.submit(func1,i).add_done_callback(func2)
import time from threading import current_thread 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)
回调函数的应用,
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from multiprocessing import Pool import requests import json import os def get_page(url): print('<进程%s> get %s' %(os.getpid(),url)) respone =requests.get(url) if respone.status_code== 200: return {'url':url,'text':respone.text} def parse_page(res): res = res.result() print('<%s> parse %s'%(os.getpid(),res['url'])) parse_res='url:<%s> size:[%s]\n'%(res['url'],len(res['text'])) with open('db.txt','a') as f: f.write(parse_res) if __name__ == '__main__': urls=[ 'https://www.baidu.com';;, 'https://www.python.org';;, 'https://www.openstack.org';;, 'https://help.github.com/';;, 'http://www.sina.com.cn/';; ] # p = Pool(3) # for url in urls: # p.apply_async(get_page,args=(url,),callback=pasrse_page) # p.close() # p.join() p=ProcessPoolExecutor(3) for url in urls: p.submit(get_page,url).add_done_callback(parse_page) # parse_page 拿到的是一个future对象obj,需要obj.result()拿到结果