python 併發 ThreadPoolExecutor

正文:
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'
"""

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章