python 使用期物处理并发
生活随笔
收集整理的這篇文章主要介紹了
python 使用期物处理并发
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1. futures.ThreadPoolExecutor
- 2. 期物
- 3. 阻塞型I/O和GIL
- 4. 使用concurrent.futures模塊啟動進程
learning from 《流暢的python》
1. futures.ThreadPoolExecutor
import os import time import sys import requestsPOP20_CC = ('CN IN US ID BR PK NG BD RU JP ' 'MX PH VN ET EG DE IR TR CD FR').split() BASE_URL = 'http://flupy.org/data/flags' DEST_DIR = './'def save_flag(img, filename): # 保存圖像path = os.path.join(DEST_DIR, filename)with open(path, 'wb') as fp:fp.write(img)def get_flag(cc): # 獲取圖像url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())resp = requests.get(url)return resp.contentdef show(text): # 打印信息print(text, end=' ')sys.stdout.flush()def download_many(cc_list):for cc in sorted(cc_list):image = get_flag(cc) # 獲取show(cc) # 打印save_flag(image, cc.lower() + '.gif') # 保存return len(cc_list)def main(download_many):t0 = time.time()count = download_many(POP20_CC)elapsed = time.time() - t0msg = '\n{} flags downloaded in {:.2f}s'print(msg.format(count, elapsed)) # 計時信息# ----使用 futures.ThreadPoolExecutor 類實現多線程下載 from concurrent import futuresMAX_WORKERS = 20 # 最多使用幾個線程def download_one(cc):image = get_flag(cc)show(cc)save_flag(image, cc.lower() + '.gif')return ccdef download_many_1(cc_list):workers = min(MAX_WORKERS, len(cc_list))with futures.ThreadPoolExecutor(workers) as executor:# 使用工作的線程數實例化 ThreadPoolExecutor 類;# executor.__exit__ 方法會調用 executor.shutdown(wait=True) 方法,# 它會在所有線程都執行完畢 前阻塞線程res = executor.map(download_one, sorted(cc_list))# download_one 函數 會在多個線程中并發調用;# map 方法返回一個生成器,因此可以迭代, 獲取各個函數返回的值return len(list(res))if __name__ == '__main__':# main(download_many) # 24 秒main(download_many_1) # 3 秒2. 期物
- 通常不應自己創建期物
- 只能由并發框架(concurrent.futures 或 asyncio)實例化
原因:期物 表示終將發生的事情,其 執行的時間 已經排定。因此,只有排定把某件事交給 concurrent.futures.Executor 子類處理時,才會創建 concurrent.futures.Future 實例
例如,Executor.submit() 方法的參數是一個可調用的對象,調用這個方法后會為傳入的可調用對象 排期,并返回一個期物
3. 阻塞型I/O和GIL
CPython 解釋器本身就不是線程安全的,因此有全局解釋器鎖(GIL), 一次只允許使用一個線程執行 Python 字節碼。因此,一個 Python 進程 通常不能同時使用多個 CPU 核心
標準庫中所有執行阻塞型 I/O 操作的函數,在等待操作系統返回結果時 都會釋放 GIL。
這意味著在 Python 語言這個層次上可以使用多線程,而 I/O 密集型 Python 程序能從中受益:一個 Python 線程等待網絡響應時,阻塞型 I/O 函數會釋放 GIL,再運行一個線程(網絡下載,文件讀寫都屬于 IO 密集型)
4. 使用concurrent.futures模塊啟動進程
這個模塊實現的是真正 的并行計算,因為它使用 ProcessPoolExecutor 類把工作分配給多個 Python 進程處理。
因此,如果需要做 CPU 密集型處理,使用這個模塊 能繞開 GIL,利用所有可用的 CPU 核心
點擊查看:進程、線程概念差異
使用 concurrent.futures 模塊能特別輕松地 把 基于線程 的方案轉成 基于進程 的方案
ProcessPoolExecutor 的價值體現在 CPU 密集型 作業上
總結
以上是生活随笔為你收集整理的python 使用期物处理并发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 1991. 找到数组的
- 下一篇: LeetCode 1799. N 次操作