正文:
Executor是一個抽象類,子類:
ThreadPoolExecutor和ProcessPoolExecutor ,一個線程池,一個進程池.
future對象:在未來的某一時刻完成操作的對象.
submit方法可以返回一個future對象,此對象直接返回,等線程函數執行完後把return的數據再set_result到future對象中;
下面實現了submit, map 與 as_completed的差別 , 下面的例子中都沒有使用with ,實際使用時需要調用shutdown , 或用with
#線程執行的函數 def add(n1,n2): v = n1 + n2 print('add :', v , ', tid:',threading.currentThread().ident) time.sleep(n1) return v #通過submit把需要執行的函數扔進線程池中. #submit 直接返回一個future對象 ex = ThreadPoolExecutor(max_workers=3) #制定最多運行N個線程 f1 = ex.submit(add,2,3) f2 = ex.submit(add,2,2) print('main thread running') print(f1.done()) #done 看看任務結束了沒 print(f1.result()) #獲取結果 ,阻塞方法
注意 map 方法,返回是跟你提交序列是一致的. 是有序的
#下面是map 方法的簡單使用. 注意:map 返回是一個生成器 ,並且是*有序的* URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn'] def get_html(url): print('thread id:',threading.currentThread().ident,' 訪問了:',url) return requests.get(url) #這裏使用了requests 模塊 ex = ThreadPoolExecutor(max_workers=3) res_iter = ex.map(get_html,URLS) #內部迭代中, 每個url 開啓一個線程 for res in res_iter: #此時將阻塞 , 直到線程完成或異常 print('url:%s ,len: %d'%(res.url,len(res.text)))
接下來,使用as_completed . 這個函數爲submit 而生, 爲啥呢?
你總想通過一種辦法來解決submit後啥時候完成的吧 , 而不是一次次調用future.done 或者 使用 future.result 吧.
concurrent.futures.as_completed(fs, timeout=None) 返回一個生成器,在迭代過程中會阻塞,
直到線程完成或者異常時,返回一個被set_result的Future對象.
同時注意, map方法返回是有序的, as_completed 是那個線程先完成/失敗 就返回
#這是一個簡單的 as_completed URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn'] def get_html(url): time.sleep(3) print('thread id:',threading.currentThread().ident,' 訪問了:',url) return requests.get(url) #這裏使用了requests 模塊 ex = ThreadPoolExecutor(max_workers=3) f = ex.submit(get_html,URLS[0]) #提交一個任務,放入線程池中,準備執行 print('main thread running') for future in as_completed([f]): #as_completed()接受一個可迭代的Future序列,返回一個生成器,在完成或異常時返回這個Future對象 print('一個任務完成.') print(future.result())
#as_completed 完整的例子 #as_completed 返回一個生成器,用於迭代, 一旦一個線程完成(或失敗) 就返回 URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn'] def get_html(url): time.sleep(1) print('thread id:',threading.currentThread().ident,' 訪問了:',url) return requests.get(url) #這裏使用了requests 模塊 ex = ThreadPoolExecutor(max_workers=3) #最多3個線程 future_tasks = [ex.submit(get_html,url) for url in URLS] #創建3個future對象 for future in as_completed(future_tasks): #迭代生成器 try: resp = future.result() except Exception as e: print('%s'%e) else: print('%s has %d bytes!'%(resp.url, len(resp.text))) """ thread id: 5160 訪問了: http://www.baidu.com thread id: 7752 訪問了: http://www.sina.com.cn thread id: 5928 訪問了: http://www.qq.com http://www.qq.com/ has 240668 bytes! http://www.baidu.com/ has 2381 bytes! https://www.sina.com.cn/ has 577244 bytes! """
wait 是阻塞函數,第一個參數和as_completed一樣, 一個可迭代的future序列,返回一個元組 ,包含2個set , 一個完成的,一個未完成的
""" wait 例子 參數: FIRST_COMPLETED 當任何未來完成或被取消時,該函數將返回。 FIRST_EXCEPTION 當任何未來通過提出異常完成時,函數將返回。如果沒有未來引發異常,那麼它等同於 ALL_COMPLETED。 ALL_COMPLETED(默認) 當所有future完成或被取消時,函數將返回。 """ URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn'] def get_html(url): time.sleep(1) print('thread id:',threading.currentThread().ident,' 訪問了:',url) return requests.get(url) #這裏使用了requests 模塊 ex = ThreadPoolExecutor(max_workers=3) #最多3個線程 future_tasks = [ex.submit(get_html,url) for url in URLS] #創建3個future對象 try: result = wait(future_tasks,return_when = fu.FIRST_COMPLETED) done_set = result[0] for future in done_set: resp = future.result() print('第一個網頁任務完成 url:%s , len:%d bytes! ' % (resp.url, len(resp.text))) except Exception as e: print('exception :' , e)
最後說一下回調:add_done_callback(fn) , 回調函數是在調用線程完成後再調用的,在同一個線程中.
import os,sys,time,requests,threading from concurrent import futures URLS = [ 'http://baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn' ] def load_url(url): print('tid:',threading.currentThread().ident,',url:',url) with requests.get(url) as resp: return resp.content def call_back(obj): print('->>>>>>>>>call_back , tid:',threading.currentThread().ident, ',obj:',obj) with futures.ThreadPoolExecutor(max_workers=3) as ex: # mp = {ex.submit(load_url,url) : url for url in URLS} mp = dict() for url in URLS: f = ex.submit(load_url,url) mp[f] = url f.add_done_callback(call_back) for f in futures.as_completed(mp): url = mp[f] try: data = f.result() except Exception as exc: print(exc, ',url:',url) else: print('url:', url, ',len:',len(data),',data[:20]:',data[:20]) """ tid: 7128 ,url: http://baidu.com tid: 7892 ,url: http://www.qq.com tid: 3712 ,url: http://www.sina.com.cn ->>>>>>>>>call_back , tid: 7892 ,obj: <Future at 0x2dd64b0 state=finished returned bytes> url: http://www.qq.com ,len: 251215 ,data[:20]: b'<!DOCTYPE html>\n<htm' ->>>>>>>>>call_back , tid: 3712 ,obj: <Future at 0x2de07b0 state=finished returned bytes> url: http://www.sina.com.cn ,len: 577333 ,data[:20]: b'<!DOCTYPE html>\n<!--' ->>>>>>>>>call_back , tid: 7128 ,obj: <Future at 0x2d533d0 state=finished returned bytes> url: http://baidu.com ,len: 81 ,data[:20]: b'<html>\n<meta http-eq' """