国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

這篇博客和你嘮嘮 python 并發(fā),滾雪球學python第四季,第16篇

qpwoeiru96 / 1047人閱讀

摘要:圖片下載屬于操作,比較耗時,基于此,可以利用中的多線程將其實現(xiàn)。更多精彩滾雪球學完結滾雪球學第二輪完結滾雪球學第三輪滾雪球學番外篇完結

在 python 編碼過程中,有時存在這樣的一個需求,同時下載 N 張圖片,并且要快。

一般這樣的需求,只需要編寫一個 for 循環(huán)即可實現(xiàn),但是加上 這個要求,就不好實現(xiàn)了。

圖片下載屬于 I/O 操作,比較耗時,基于此,可以利用 python 中的多線程將其實現(xiàn)。

為了不讓大家學的太困倦,特意找來 6 張美麗的圖片,本次學習將圍繞這幾張圖片進行。

https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv.jpghttps://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-004.jpghttps://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-012.jpghttps://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-013.jpghttps://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-016.jpghttps://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-010.jpg

單線程下載 6 張圖片

使用 for 循環(huán),同步代碼如下所示:

import timeimport requestsurls = [    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-004.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-012.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-013.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-016.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-010.jpg"]# 文件保存路徑SAVE_DIR = "./928/"def save_img(url):    res = requests.get(url)    with open(F"{SAVE_DIR}{time.time()}.jpg", "wb+") as f:        f.write(res.content)if __name__ == "__main__":    # 下載開始時間    start_time = time.perf_counter()    for url in urls:        save_img(url)    print("下載 6 張圖片消耗時間為:", time.perf_counter() - start_time)    # 下載 6 張圖片消耗時間為: 1.911142665

concurrent.futures 模塊下載 6 張圖片

接下來使用 concurrent.futures 模塊 實現(xiàn)對 6 張圖片的下載,這個模塊實現(xiàn)了 ThreadPoolExecutor 類和 ProcessPoolExecutor 類,都繼承自Executor,分別被用來創(chuàng)建 線程池進程池,接受 max_workers 參數,代表創(chuàng)建的線程數或者進程數。

這兩個類可以在不同的線程或進程中執(zhí)行 可調用對象ProcessPoolExecutormax_workers 參數可以為空,程序會自動創(chuàng)建與電腦 CPU數目相同的進程數。

使用 ThreadPoolExecutor 實現(xiàn)多線程下載

import timeimport requestsfrom concurrent import futuresMAX_WORKERS = 20  # 最大線程數SAVE_DIR = "./928/"  # 文件保存路徑urls = [    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-004.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-012.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-013.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-016.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-010.jpg"]def save_img(url):    res = requests.get(url)    with open(F"{SAVE_DIR}{time.time()}.jpg", "wb+") as f:        f.write(res.content)if __name__ == "__main__":    start_time = time.perf_counter()  # 下載開始時間    with futures.ThreadPoolExecutor(MAX_WORKERS) as executor:        res = executor.map(save_img, urls) # executor.map() 方法會返回一個生成器,后續(xù)代碼可以迭代獲取每個線程的執(zhí)行結果    print("下載 6 張圖片消耗時間為:", time.perf_counter() - start_time)    # 下載 6 張圖片消耗時間為: 0.415939759

當使用多線程代碼之后,時間從單線程的 1.9s 變?yōu)榱硕嗑€程的 0.4s,能看到效率的提升。

Future 類

在上述多線程代碼中,使用了 concurrent 庫中的 future 對象,該對象是 Future 類的對象,它的實力表示可能已經完成尚未完成的 延遲計算,該類具備 done() 方法,返回調用對象是否已經執(zhí)行,有該方法的同時還具備一個 add_done_callback() 方法,表示調用對象執(zhí)行完畢的回調函數。

from concurrent.futures import ThreadPoolExecutordef print_name():    return "橡皮擦"def say_hello(obj):    """可調用對象執(zhí)行完畢,綁定的回調函數"""    w_name = obj.result()    s = w_name + "你好"    print(s)    return swith ThreadPoolExecutor(1) as executor:    executor.submit(print_name).add_done_callback(say_hello)

在上述代碼中用到了如下知識點:

  • executor.map():該方法類似 map 函數,原型為 map(func, *iterables, timeout=None, chunksize=1),異步執(zhí)行 func,并支持多次并發(fā)調用;
  • executor.submit():方法原型為 submit(fn, *args, **kwargs),安排可調用對象 fnfn(*args, **kwargs) 的形式執(zhí)行,并返回 Future 對象來表示它的執(zhí)行結果,該方法只能進行單個任務,如果需要并發(fā)多個任務,需要使用 map 或者 as_completed
  • future對象.result():返回調用返回的值,有個等待時間參數 timeout 可以設置;
  • future對象add_done_callback():該方法中綁定的回調函數在 future 取消或者完成后運行,表示 future 本身

補充說明

as_completed() 方法
該方法參數是一個 Future 列表,返回值是一個 Future 組成的生成器,在調用 as_completed() 方法時不會阻塞,只有當對迭代器進行循環(huán)時,每調用一次 next() 方法,如果當前 Future 對象還未完成,則會阻塞。

修改下載 6 張圖片的代碼,使用 as_completed() 進行實現(xiàn),最后得到的時間優(yōu)于單線程,但如果對結果進行迭代,調用 result() 方法,則時間會加長。

import timeimport requestsfrom concurrent.futures import ThreadPoolExecutor, as_completedMAX_WORKERS = 20  # 最大線程數SAVE_DIR = "./928/"  # 文件保存路徑urls = [    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-004.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-012.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-013.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-016.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-010.jpg"]def save_img(url):    res = requests.get(url)    with open(F"{SAVE_DIR}{time.time()}.jpg", "wb+") as f:        f.write(res.content)if __name__ == "__main__":    start_time = time.perf_counter()  # 下載開始時間    with ThreadPoolExecutor(MAX_WORKERS) as executor:        tasks = [executor.submit(save_img, url) for url in urls]        # 去除下部分代碼,時間基本與 map 一致。        for future in as_completed(tasks):            print(future.result())    print("下載 6 張圖片消耗時間為:", time.perf_counter() - start_time)    # 下載 6 張圖片消耗時間為: 0.840261401

wait 方法
wait 方法可以讓主線程阻塞,直到滿足設定的要求,該要求為 return_when 參數,其值有 ALL_COMPLETEDFIRST_COMPLETEDFIRST_EXCEPTION

import timeimport requestsfrom concurrent.futures import ThreadPoolExecutor, as_completed, wait, ALL_COMPLETED, FIRST_COMPLETEDMAX_WORKERS = 20  # 最大線程數SAVE_DIR = "./928/"  # 文件保存路徑urls = [    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-004.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-012.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-013.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-016.jpg",    "https://img-pre.ivsky.com/img/tupian/pre/202102/21/oumei_meinv-010.jpg"]def save_img(url):    res = requests.get(url)    with open(F"{SAVE_DIR}{time.time()}.jpg", "wb+") as f:        f.write(res.content)if __name__ == "__main__":    start_time = time.perf_counter()  # 下載開始時間    with ThreadPoolExecutor(MAX_WORKERS) as executor:        tasks = [executor.submit(save_img, url) for url in urls]        wait(tasks, return_when=ALL_COMPLETED)        print("程序運行完畢")    print("下載 6 張圖片消耗時間為:", time.perf_counter() - start_time)    # 下載 6 張圖片消耗時間為: 0.48876672

最后一句:ProcessPoolExecutor 的用法與 ThreadPoolExecutor 的用法基本一致,所以可以互通。

寫在后面

以上內容就是本文的全部內容,希望對學習路上的你有所幫助~

今天是持續(xù)寫作的第 235 / 365 天。
期待 關注點贊評論收藏

更多精彩

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/122205.html

相關文章

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<