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

歡迎訪問 生活随笔!

生活随笔

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

python

Python Map 并行

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

Map是一個(gè)酷酷的小東西,也是在Python代碼輕松引入并行的關(guān)鍵。對(duì)此不熟悉的人會(huì)認(rèn)為map是從函數(shù)式語言(如Lisp)借鑒來的東西。map是一個(gè)函數(shù) - 將另一個(gè)函數(shù)映射到一個(gè)序列上。例如:

urls = ['http://www.yahoo.com', 'http://www.reddit.com'] results = map(urllib2.urlopen, urls)

?

這段代碼在傳入序列的每個(gè)元素上應(yīng)用方法urlopen,并將所有結(jié)果存入一個(gè)列表中。大致與下面這段代碼的邏輯相當(dāng):

results = [] for url in urls: results.append(urllib2.urlopen(url))

?

Map會(huì)為我們處理在序列上的迭代,應(yīng)用函數(shù),最后將結(jié)果存入一個(gè)方便使用的列表。

這為什么重要呢?因?yàn)槔们‘?dāng)?shù)膸?kù),map讓并行處理成為小事一樁!

Python標(biāo)準(zhǔn)庫(kù)中multiprocessing模塊,以及極少人知但同樣出色的子模塊multiprocessing.dummy,提供了map函數(shù)的并行版本。

題外話:這是啥?你從未聽說過這名為dummy的mulprocessing模塊的線程克隆版本?我也是最近才知道的。在multiprocessing文檔頁中僅有一句提到這個(gè)子模塊,而這句話基本可以歸結(jié)為“哦,是的,存在這樣一個(gè)東西”。完全低估了這個(gè)模塊的價(jià)值!

Dummy是multiprocessing模塊的精確克隆,唯一的區(qū)別是:multiprocessing基于進(jìn)程工作,而dummy模塊使用線程(也就帶來了常見的Python限制)。因此,任何東西可套用到一個(gè)模塊,也就可以套用到另一個(gè)模塊。在兩個(gè)模塊之間來回切換也就相當(dāng)容易,當(dāng)你不太確定一些框架調(diào)用是IO密集型還是CPU密集型時(shí),想做探索性質(zhì)的編程,這一點(diǎn)會(huì)讓你覺得非常贊!

開始

為了訪問map函數(shù)的并行版本,首先需要導(dǎo)入包含它的模塊:

# 以下兩行引入其一即可 from multiprocessing import Pool from multiprocessing.dummy import Pool as ThreadPool

?

并實(shí)例化池對(duì)象:

# 譯注:這里其實(shí)是以dummy模塊為例 pool = ThreadPool()

?

這一句代碼處理了example2.py中7行的build_worker_pool函數(shù)完成的所有事情。如名所示,這句代碼會(huì)創(chuàng)建一組可用的工作者,啟動(dòng)它們來準(zhǔn)備工作,并將它們存入變量中,方便訪問。

pool對(duì)象可以有若干參數(shù),但目前,只需關(guān)注第一個(gè):進(jìn)程/線程數(shù)量。這個(gè)參數(shù)用于設(shè)置池中的工作者數(shù)目。如果留空,默認(rèn)為機(jī)器的CPU核數(shù)。

一般來說,如果為CPU密集型任務(wù)使用進(jìn)程池(multiprocessing pool),更多的核等于更快的速度(但有一些注意事項(xiàng))。然而,當(dāng)使用線程池(threading)處理網(wǎng)絡(luò)密集型任務(wù)時(shí),情況就很不一樣了,因此最好試驗(yàn)一下池的最佳大小。

pool = ThreadPool(4) # 將池的大小設(shè)置為4

?

如果運(yùn)行了過多的線程,就會(huì)浪費(fèi)時(shí)間在線程切換上,而不是做有用的事情,所以可以把玩把玩直到找到最適合任務(wù)的線程數(shù)量。

現(xiàn)在池對(duì)象創(chuàng)建好了,簡(jiǎn)單的并行也是彈指之間的事情了,那來重寫example2.py吧。

import urllib2 from multiprocessing.dummy import Pool as ThreadPool urls = ['http://www.python.org', 'http://www.python.org/about/','http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html','http://www.python.org/doc/','http://www.python.org/download/','http://www.python.org/getit/','http://www.python.org/community/','https://wiki.python.org/moin/','http://planet.python.org/','https://wiki.python.org/moin/LocalUserGroups','http://www.python.org/psf/','http://docs.python.org/devguide/','http://www.python.org/community/awards/'# 等等... ]# 創(chuàng)建一個(gè)工作者線程池 pool = ThreadPool(4) # 在各個(gè)線程中打開url,并返回結(jié)果 results = pool.map(urllib2.urlopen, urls) #close the pool and wait for the work to finish # 關(guān)閉線程池,等待工作結(jié)束 pool.close() pool.join()

?

看看!真正做事情的代碼僅有4行,其中3行只是簡(jiǎn)單的輔助功能。map調(diào)用輕松搞定了之前示例40行代碼做的事情!覺得好玩,我對(duì)兩種方式進(jìn)行了時(shí)間測(cè)量,并使用了不同的池大小。

# 譯注:我覺得與串行處理方式對(duì)比意義不大,應(yīng)該和隊(duì)列的方式進(jìn)行性能對(duì)比 results = [] for url in urls:result = urllib2.urlopen(url)results.append(result)# # ------- 對(duì)比 ------- # # # ------- 池的大小為4 ------- # pool = ThreadPool(4) results = pool.map(urllib2.urlopen, urls)# # ------- 池的大小為8 ------- # pool = ThreadPool(8) results = pool.map(urllib2.urlopen, urls)# # ------- 池的大小為13 ------- # pool = ThreadPool(13) results = pool.map(urllib2.urlopen, urls)

?

結(jié)果:

單線程: 14.4 秒 池大小為4時(shí):3.1 秒 池大小為8時(shí):1.4 秒 池大小為13時(shí):1.3秒

真是呱呱叫啊!也說明了試驗(yàn)不同的池大小是有必要的。在我的機(jī)器上,池的大小大于9后會(huì)導(dǎo)致性能退化(譯注:咦,結(jié)果不是顯示13比8的性能要好么?)。

現(xiàn)實(shí)中的Example 2

為千張圖片創(chuàng)建縮略圖。

來做點(diǎn)CPU密集型的事情!對(duì)于我,在工作中常見的任務(wù)是操作大量的圖片目錄。其中一種圖片轉(zhuǎn)換是創(chuàng)建縮略圖。這項(xiàng)工作適于并行處理。

基本的單進(jìn)程設(shè)置

from multiprocessing import Pool from PIL import ImageSIZE = (75,75) SAVE_DIRECTORY = 'thumbs'def get_image_paths(folder):return (os.path.join(folder, f) for f in os.listdir(folder) if 'jpeg' in f)def create_thumbnail(filename): im = Image.open(filename)im.thumbnail(SIZE, Image.ANTIALIAS)base, fname = os.path.split(filename) save_path = os.path.join(base, SAVE_DIRECTORY, fname)im.save(save_path)if __name__ == '__main__':folder = os.path.abspath('11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840')os.mkdir(os.path.join(folder, SAVE_DIRECTORY))images = get_image_paths(folder)for image in images: create_thumbnail(image)

?

示例代碼中用了一些技巧,但大體上是:向程序傳入一個(gè)目錄,從目錄中獲取所有圖片,然后創(chuàng)建縮略圖,并將縮略圖存放到各自的目錄中。

在我的機(jī)器上,這個(gè)程序處理大約6000張圖片,花費(fèi)27.9秒。

如果使用一個(gè)并行的map調(diào)用來替換for循環(huán):

from multiprocessing import Pool from PIL import ImageSIZE = (75,75) SAVE_DIRECTORY = 'thumbs'def get_image_paths(folder):return (os.path.join(folder, f) for f in os.listdir(folder) if 'jpeg' in f)def create_thumbnail(filename): im = Image.open(filename)im.thumbnail(SIZE, Image.ANTIALIAS)base, fname = os.path.split(filename) save_path = os.path.join(base, SAVE_DIRECTORY, fname)im.save(save_path)if __name__ == '__main__':folder = os.path.abspath('11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840')os.mkdir(os.path.join(folder, SAVE_DIRECTORY))images = get_image_paths(folder)pool = Pool()pool.map(create_thumbnail, images)pool.close() pool.join()

?

5.6秒!

僅修改幾行代碼就能得到巨大的速度提升。這個(gè)程序的生產(chǎn)環(huán)境版本通過切分CPU密集型工作和IO密集型工作并分配到各自的進(jìn)程和線程(通常是死鎖代碼的一個(gè)因素),獲得更快的速度。然而,由于map性質(zhì)清晰明確,無需手動(dòng)管理線程,以干凈、可靠、易于調(diào)試的方式混合匹配兩者(譯注:這里的“兩者”是指什么?CPU密集型工作和IO密集型工作?),也是相當(dāng)容易的。

就是這樣了。(幾乎)一行式并行解決方案。

?

轉(zhuǎn)自:http://blog.xiayf.cn/2015/09/11/parallelism-in-one-line/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

?

轉(zhuǎn)載于:https://www.cnblogs.com/wangxusummer/p/4835929.html

總結(jié)

以上是生活随笔為你收集整理的Python Map 并行的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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