日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python 使用期物处理并发

發(fā)布時(shí)間:2024/7/5 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 使用期物处理并发 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 1. futures.ThreadPoolExecutor
    • 2. 期物
    • 3. 阻塞型I/O和GIL
    • 4. 使用concurrent.futures模塊啟動(dòng)進(jìn)程

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)) # 計(jì)時(shí)信息# ----使用 futures.ThreadPoolExecutor 類實(shí)現(xiàn)多線程下載 from concurrent import futuresMAX_WORKERS = 20 # 最多使用幾個(gè)線程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:# 使用工作的線程數(shù)實(shí)例化 ThreadPoolExecutor 類;# executor.__exit__ 方法會(huì)調(diào)用 executor.shutdown(wait=True) 方法,# 它會(huì)在所有線程都執(zhí)行完畢 前阻塞線程res = executor.map(download_one, sorted(cc_list))# download_one 函數(shù) 會(huì)在多個(gè)線程中并發(fā)調(diào)用;# map 方法返回一個(gè)生成器,因此可以迭代, 獲取各個(gè)函數(shù)返回的值return len(list(res))if __name__ == '__main__':# main(download_many) # 24 秒main(download_many_1) # 3 秒

2. 期物

  • 通常不應(yīng)自己創(chuàng)建期物
  • 只能由并發(fā)框架(concurrent.futures 或 asyncio)實(shí)例化
    原因:期物 表示終將發(fā)生的事情,其 執(zhí)行的時(shí)間 已經(jīng)排定。因此,只有排定把某件事交給 concurrent.futures.Executor 子類處理時(shí),才會(huì)創(chuàng)建 concurrent.futures.Future 實(shí)例
    例如,Executor.submit() 方法的參數(shù)是一個(gè)可調(diào)用的對象,調(diào)用這個(gè)方法后會(huì)為傳入的可調(diào)用對象 排期,并返回一個(gè)期物
def download_many_2(cc_list):cc_list = cc_list[:5]with futures.ThreadPoolExecutor(max_workers=3) as executor:to_do = []for cc in sorted(cc_list):future = executor.submit(download_one, cc)# executor.submit 方法排定可調(diào)用對象的執(zhí)行時(shí)間,# 然后返回一個(gè) 期物,表示這個(gè)待執(zhí)行的操作to_do.append(future) # 存儲(chǔ)各個(gè)期物msg = 'Scheduled for {}: {}'print(msg.format(cc, future))results = []for future in futures.as_completed(to_do):# as_completed 函數(shù)在期物運(yùn)行結(jié)束后產(chǎn)出期物res = future.result() # 獲取期物的結(jié)果msg = '{} result: {!r}'print(msg.format(future, res))results.append(res)return len(results) 輸出: Scheduled for BR: <Future at 0x22da99d2d30 state=running> Scheduled for CN: <Future at 0x22da99e1040 state=running> Scheduled for ID: <Future at 0x22da99e1b20 state=running> Scheduled for IN: <Future at 0x22da99ec520 state=pending> Scheduled for US: <Future at 0x22da99ecd00 state=pending> CN <Future at 0x22da99e1040 state=finished returned str> result: 'CN' BR <Future at 0x22da99d2d30 state=finished returned str> result: 'BR' ID <Future at 0x22da99e1b20 state=finished returned str> result: 'ID' IN <Future at 0x22da99ec520 state=finished returned str> result: 'IN' US <Future at 0x22da99ecd00 state=finished returned str> result: 'US'5 flags downloaded in 3.20s

3. 阻塞型I/O和GIL

CPython 解釋器本身就不是線程安全的,因此有全局解釋器鎖(GIL), 一次只允許使用一個(gè)線程執(zhí)行 Python 字節(jié)碼。因此,一個(gè) Python 進(jìn)程 通常不能同時(shí)使用多個(gè) CPU 核心

標(biāo)準(zhǔn)庫中所有執(zhí)行阻塞型 I/O 操作的函數(shù),在等待操作系統(tǒng)返回結(jié)果時(shí) 都會(huì)釋放 GIL
這意味著在 Python 語言這個(gè)層次上可以使用多線程,而 I/O 密集型 Python 程序能從中受益:一個(gè) Python 線程等待網(wǎng)絡(luò)響應(yīng)時(shí),阻塞型 I/O 函數(shù)會(huì)釋放 GIL,再運(yùn)行一個(gè)線程(網(wǎng)絡(luò)下載,文件讀寫都屬于 IO 密集型)

4. 使用concurrent.futures模塊啟動(dòng)進(jìn)程

這個(gè)模塊實(shí)現(xiàn)的是真正 的并行計(jì)算,因?yàn)樗褂?ProcessPoolExecutor 類把工作分配給多個(gè) Python 進(jìn)程處理。
因此,如果需要做 CPU 密集型處理,使用這個(gè)模塊 能繞開 GIL,利用所有可用的 CPU 核心

點(diǎn)擊查看:進(jìn)程、線程概念差異

使用 concurrent.futures 模塊能特別輕松地 把 基于線程 的方案轉(zhuǎn)成 基于進(jìn)程 的方案

ProcessPoolExecutor 的價(jià)值體現(xiàn)在 CPU 密集型 作業(yè)上

總結(jié)

以上是生活随笔為你收集整理的python 使用期物处理并发的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。