<table id="qs2qo"></table>
  • <bdo id="qs2qo"><center id="qs2qo"></center></bdo>
    • 自動秒收錄
    • 軟件:1973
    • 資訊:56215|
    • 收錄網站:181187|

    IT精英團

    一行Python代碼實現程序并行

    一行Python代碼實現程序并行

    瀏覽次數:
    評論次數:
    編輯: 溫瑜
    信息來源: ITPUB
    更新日期: 2022-05-12 18:32:52
    摘要

    Python在程序并行化方面多少有些聲名狼藉。撇開技術上的問題,例如線程的實現和GIL,我覺得錯誤的教學指導才是主要問題。常見的經典Python多線程、多進程教程多顯得偏"重"。而且往往隔靴搔

    • 正文開始
    • 相關閱讀
    • 推薦作品

    Python在并行化程序方面有些臭名昭著。拋開技術問題,比如線程和GIL的實現,我認為錯誤的教學指導是主要問題。常見的經典Python多線程和多進程教程往往比較‘沉重’。而且他們經常抓靴搔癢,不深入討論日常工作中最有用的內容。

    傳統的例子

    簡單搜索Python多線程教程’,不難發現幾乎所有教程都給出了涉及類和隊列的例子:

    導入操作系統

    進口PIL

    從多處理導入池

    從PIL進口圖片

    大小=(75,75)

    SAVE_DIRECTORY='thumbs '

    def獲取圖像路徑(文件夾):

    return (os.path.join(文件夾,f)

    for f in os.listdir(文件夾)

    如果f)中的“jpeg”

    定義創建縮略圖(文件名):

    im=Image.open(文件名)

    im.thumbnail(大小,圖像??逛忼X)

    base,fname=os.path.split(文件名)

    save_path=os.path.join(base,SAVE_DIRECTORY,fname)

    im.save(保存路徑)

    if __name__=='__main__':

    folder=os.path.abspath(

    11 _ 18 _ 2013 _ R000 _ IQM _ Big _ Sur _ Mon _ _ e10d 1958 E7 b 766 C3 e 840 ')

    os.mkdir(os.path.join(文件夾,保存目錄))

    images=get_image_paths(文件夾)

    pool=Pool()

    pool.map(創建縮略圖,圖像)

    pool.close()

    pool.join()

    哈,看起來有點像Java吧?

    我并不是說用生產者/消費者模型來處理多線程/多進程任務是錯誤的(其實這個模型有它自己的用處)。但是,在處理日常腳本任務時,我們可以使用更高效的模型。

    問題在于…

    首先,你需要一個模板類;

    其次,你需要一個隊列來傳遞對象;

    而且,你需要在通道兩端建立相應的方法來幫助它工作(如果你想雙向通信或者保存結果,你需要引入另一個隊列)。

    worker 越多,問題越多

    根據這個想法,您現在需要一個工作線程的線程池。下面是一個IBM經典教程中的——的例子,在搜索網頁時用多線程加速。

    #示例2.py

    '''

    一個更現實的線程池示例

    '''

    導入時間

    導入線程

    導入隊列

    導入urllib2

    類消費者(線程。螺紋):

    def __init__(自身,隊列):

    threading.Thread.__init__(self)

    自我。_queue=隊列

    定義運行(自身):

    而True:

    內容=自我。_queue.get()

    如果是意大利

    nce(content, str) and content == 'quit':
                   break
               response = urllib2.urlopen(content)
           print 'Bye byes!'

    def Producer():
       urls = [
           'http://www.python.org', 'http://www.yahoo.com'
           'http://www.scala.org', 'http://www.google.com'
           # etc..
       ]
       queue = Queue.Queue()
       worker_threads = build_worker_pool(queue, 4)
       start_time = time.time()

       # Add the urls to process
       for url in urls:
           queue.put(url)  
       # Add the poison pillv
       for worker in worker_threads:
           queue.put('quit')
       for worker in worker_threads:
           worker.join()

       print 'Done! Time taken: {}'.format(time.time() - start_time)

    def build_worker_pool(queue, size):
       workers = []
       for _ in range(size):
           worker = Consumer(queue)
           worker.start()
           workers.append(worker)
       return workers

    if __name__ == '__main__':
       Producer()

    這段代碼能正確的運行,但仔細看看我們需要做些什么:構造不同的方法、追蹤一系列的線程,還有為了解決惱人的死鎖問題,我們需要進行一系列的 join 操作。這還只是開始……

    至此我們回顧了經典的多線程教程,多少有些空洞不是嗎?樣板化而且易出錯,這樣事倍功半的風格顯然不那么適合日常使用,好在我們還有更好的方法。

    何不試試 map

    map 這一小巧精致的函數是簡捷實現 Python 程序并行化的關鍵。map 源于 Lisp 這類函數式編程語言。它可以通過一個序列實現兩個函數之間的映射。

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

    上面的這兩行代碼將 urls 這一序列中的每個元素作為參數傳遞到 urlopen 方法中,并將所有結果保存到 results 這一列表中。其結果大致相當于:

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

    map 函數一手包辦了序列操作、參數傳遞和結果保存等一系列的操作。

    為什么這很重要呢?這是因為借助正確的庫,map 可以輕松實現并行化操作。

    在 Python 中有個兩個庫包含了 map 函數:multiprocessing 和它鮮為人知的子庫 multiprocessing.dummy.

    這里多扯兩句:multiprocessing.dummy?mltiprocessing 庫的線程版克???這是蝦米?即便在 multiprocessing 庫的官方文檔里關于這一子庫也只有一句相關描述。而這句描述譯成人話基本就是說:"嘛,有這么個東西,你知道就成."相信我,這個庫被嚴重低估了!

    dummy 是 multiprocessing 模塊的完整克隆,唯一的不同在于 multiprocessing 作用于進程,而 dummy 模塊作用于線程(因此也包括了 Python 所有常見的多線程限制)。 
    所以替換使用這兩個庫異常容易。你可以針對 IO 密集型任務和 CPU 密集型任務來選擇不同的庫。

    動手嘗試

    使用下面的兩行代碼來引用包含并行化 map 函數的庫:

    from multiprocessing import Pool
    from multiprocessing.dummy import Pool as ThreadPool

    實例化 Pool 對象:

    pool = ThreadPool()

    這條簡單的語句替代了 example2.py 中 buildworkerpool 函數 7 行代碼的工作。它生成了一系列的 worker 線程并完成初始化工作、將它們儲存在變量中以方便訪問。

    Pool 對象有一些參數,這里我所需要關注的只是它的第一個參數:processes. 這一參數用于設定線程池中的線程數。其默認值為當前機器 CPU 的核數。

    一般來說,執行 CPU 密集型任務時,調用越多的核速度就越快。但是當處理網絡密集型任務時,事情有有些難以預計了,通過實驗來確定線程池的大小才是明智的。

    pool = ThreadPool(4) # Sets the pool size to 4

    線程數過多時,切換線程所消耗的時間甚至會超過實際工作時間。對于不同的工作,通過嘗試來找到線程池大小的最優值是個不錯的主意。

    創建好 Pool 對象后,并行化的程序便呼之欲出了。我們來看看改寫后的 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/'
       # etc..
       ]

    # Make the Pool of workers
    pool = ThreadPool(4)
    # Open the urls in their own threads
    # and return the results
    results = pool.map(urllib2.urlopen, urls)
    #close the pool and wait for the work to finish
    pool.close()
    pool.join()

    實際起作用的代碼只有 4 行,其中只有一行是關鍵的。map 函數輕而易舉的取代了前文中超過 40 行的例子。為了更有趣一些,我統計了不同方法、不同線程池大小的耗時情況。

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

    # # ------- VERSUS ------- #

    # # ------- 4 Pool ------- #
    # pool = ThreadPool(4)
    # results = pool.map(urllib2.urlopen, urls)

    # # ------- 8 Pool ------- #

    # pool = ThreadPool(8)
    # results = pool.map(urllib2.urlopen, urls)

    # # ------- 13 Pool ------- #

    # pool = ThreadPool(13)
    # results = pool.map(urllib2.urlopen, urls)

    結果:

    #        Single thread:  14.4 Seconds 
    #               4 Pool:   3.1 Seconds
    #               8 Pool:   1.4 Seconds
    #              13 Pool:   1.3 Seconds

    很棒的結果不是嗎?這一結果也說明了為什么要通過實驗來確定線程池的大小。在我的機器上當線程池大小大于 9 帶來的收益就十分有限了。

    另一個真實的例子

    生成上千張圖片的縮略圖 
    這是一個 CPU 密集型的任務,并且十分適合進行并行化。

    基礎單進程版本

    import os 
    import PIL

    from multiprocessing import Pool
    from PIL import Image

    SIZE = (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)

    上邊這段代碼的主要工作就是將遍歷傳入的文件夾中的圖片文件,一一生成縮略圖,并將這些縮略圖保存到特定文件夾中。

    這我的機器上,用這一程序處理 6000 張圖片需要花費 27.9 秒。

    如果我們使用 map 函數來代替 for 循環:

    import os 
    import PIL

    from multiprocessing import Pool
    from PIL import Image

    SIZE = (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(creat_thumbnail, images)
       pool.close()
       pool.join()

    5.6 秒!

    雖然只改動了幾行代碼,我們卻明顯提高了程序的執行速度。在生產環境中,我們可以為 CPU 密集型任務和 IO 密集型任務分別選擇多進程和多線程庫來進一步提高執行速度——這也是解決死鎖問題的良方。此外,由于 map 函數并不支持手動線程管理,反而使得相關的 debug 工作也變得異常簡單。

    到這里,我們就實現了(基本)通過一行 Python 實現并行化。

    譯者:caspar

    譯文:https://segmentfault.com/a/1190000000414339 

    原文:https://medium.com/building-things-on-the-internet/40e9b2b36148



    標簽:線程 這一 函數
    用Ansible實現MySQL的備份、操作和維護
    ? 上一篇 2022-05-11
    epoll這個Linux高性能服務的本質真的不簡單
    下一篇 ? 2022-05-12
    • 胡迪核心知識點詳解(好文章合集)
      1閱讀 0條評論 個贊
      以下文章來源于公眾號-3分鐘秒懂大數據,作者在IT中穿梭旅行在Flink實時流中,經常會通過FlinkCDC插件讀取Mysql數據,然后寫入Hudi中。所以在執行上述操作時,需要了解……
    • 前端面試必須解決網絡中的跨域問題
      0閱讀 0條評論 個贊
      什么是跨域瀏覽器有一個重要的安全策略,稱之為「同源策略」其中,源=協議+主機+端口源=協議+主機+端口源=協議+主機+端口,兩個源相同,稱之為同源,兩個源不同,稱之為跨源或跨域比如:源1源2是否同……
    • 如何在Bash腳本中使用強大的Linux測試命令
      0閱讀 0條評論 個贊
      Linuxtest命令是Shell內置命令,用來檢測某個條件是否成立。test通常和if語句一起使用,并且大部分if語句都依賴test??梢詫⒁粋€元素與另一個元素進行比較,但它更?!?/div>
    • 真正的建筑設計是什么樣子的?
      1閱讀 0條評論 個贊
      什么是架構和架構本質在軟件行業,對于什么是架構,都有很多的爭論,每個人都有自己的理解。此君說的架構和彼君理解的架構未必是一回事。因此我們在討論架構之前,我們先討論架構的概念定義,概念是人認識這個世界的……
    • 10分鐘了解云原生 值得收藏~
      0閱讀 0條評論 個贊
      文章轉載:奇妙的Linux世界我們已經進入云計算下半場,不再像上半場在糾結要不要上云,而是討論怎么上云?才能把云計算的價值發揮到淋漓盡致。如何把云計算與不同的業務場景深度結合?如何讓技術真正作用于企業……
    發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    • PostgreSQL并行框架分析
      3閱讀 0條評論 個贊
      作者簡介施博文,目前就職于騰訊云PG團隊概覽PostgreSQL并行框架提供了一系列方便的函數,支持在插件或內核中直接調用相關函數,啟動若干個后臺進程進行并行操作。目前,PG的并行框架主要用來……
    • 3種方式!轉到錯誤處理最佳實踐
      1閱讀 0條評論 個贊
      以下文章來源于公眾號-云加社區,作者李森林導語|錯誤處理一直以一是編程必需要面對的問題,錯誤處理如果做的好的話,代碼的穩定性會很好。不同的語言有不同的出現處理的方式。Go語言也一樣,在本篇文章中,我們……
    • 數據治理 區分系統、機制、流程的概念很重要
      0閱讀 0條評論 個贊
      以下文章來源于公眾號-大魚的數據人生,作者討厭的大魚先生我們剛接觸數據的時候,從事的大多是具體的數據管理活動,無論是數據的采集、開發和開放,或是元數據管理、數據質量管理或是數據安全管理等等,但當你想更……
    • 如何用10行bash shell腳本監控Linux?
      1閱讀 0條評論 個贊
      http://985.so/xbtd子沐愛掃地(譯)監控我們的環境對于服務器運維來說至關重要,尤其是在部署新的應用程序時。如今,公司每天都使用開源解決方案來監控系統資源。但是,當出于測試的目的來監控……
    • Redis過期的數據會被立即刪除嗎?
      1閱讀 0條評論 個贊
      本文來源碼哥字節(ID:MageByte)?碼哥,當key達到過期時間,Redis就會馬上刪除么?先說結論:并不會立馬刪除。Redis有兩種刪除過期數據的策略:定期選取部分數據刪除;惰性刪除;……
    • 數據倉庫實踐:總線矩陣體系結構的設計
      1閱讀 0條評論 個贊
      以下文章來源于公眾號-云祁的數據江湖,作者云祁如何設計一套切實可行的數據倉庫呢?我們要明白,對于數據倉庫的設計是不能完全依賴于業務的需求,但往往又必須要服務于業務的價值。因此,在構建數據倉庫前,我們……
    • 提高Java字符串編碼和解碼性能的技巧
      1閱讀 0條評論 個贊
      1常見字符串編碼●常見的字符串編碼有:LATIN1只能保存ASCII字符,又稱ISO-8859-1。UTF-8變長字節編碼,一個字符需要使用1個、2個或者3個byte表示。由于中文通常需要3個字節……
    • Java處理異常的9個最佳實踐 你做得對嗎?
      1閱讀 0條評論 個贊
      原文:https://dzone.com/articles/9-best-practices-to-handle-exceptions-in-java譯者:颯然Hang譯文:http://www.r……
    • 運維常用的34個Linux Shell腳本 對你一定有幫助!
      1閱讀 0條評論 個贊
      作為一名Linux工程師,會寫好的腳本不僅能提高工作效率,還能有更多的時間做自己的事。最近在網上沖浪的時候,也注意收集一些大佬寫過的腳本,匯總整理一下,歡迎收藏,與君共勉?。?)用戶猜數字#!/b……
    • 操作系統宕機 如何找回我的MySQL記錄?
      0閱讀 0條評論 個贊
      以下文章來源于公眾號-數據和云,作者楊豹一、概述如果Linux操作系統宕機,啟動不了,救援模式(rescueinstalledsystem)也行不通的時候,那么該機器上的MySQL數據還能恢復嗎?……
    • 卡夫卡3.0新功能全暴露 好香??!
      1閱讀 0條評論 個贊
      以下文章來源于云加社區,作者屈志平導語|kafka3.0的版本已經試推行去zk的kafka架構了,如果去掉了zk,那么在kafka新的版本當中使用什么技術來代替了zk的位置呢,接下來我們一起來一探究竟……
    • Linux中的交互式進程查看命令htop
      1閱讀 0條評論 個贊
      htop界面展示HtopLinux進程監控工具“Htop是一個用于Linux/類Unix系統的交互式實時進程監控應用程序,也是top命的替代品,它是所有Linux操作系統上預裝的默……
    • MySQL支持哈希索引嗎?(收藏)
      1閱讀 0條評論 個贊
      經常有朋友問,MySQL的InnoDB到底支不支持哈希索引?對于InnoDB的哈希索引,確切的應該這么說:(1)InnoDB用戶無法手動創建哈希索引,這一層上說,InnoDB確實不支持哈希索引;(2)……
    • 詳細解釋Linux中的diff命令和例子
      1閱讀 0條評論 個贊
      文件比較在Linux中起著重要的作用,特別是對于程序員和Linux系統管理員。例如,如果您想找到兩個源代碼文件之間的差異來開發補丁,那么您需要一個文件比較工具來簡化這個過程。Linux中有幾……
    • 高可用性架構設計的無狀態服務
      2閱讀 0條評論 個贊
      笑談架構設計事故的發生是量的積累的結果,任何事情都沒有表面看起來那么簡單,在軟件運行的過程中,隨著用戶量的增加,不考慮高可用,遲早有一天會發生故障,不得事先考慮高可用設計,而高可用是一門龐大的學問。在……
    • 可以解決80%問題的故障排除思路
      0閱讀 0條評論 個贊
      在講解事件、故障處理思路前,先講一個故障場景(以呼叫中心系統作為一例子):業務人員反映呼叫中心系統運行緩慢,部份電話在自助語言環節系統處理超時,話務轉人工座席,人工座席出現爆線情況。運維人員開始忙活了……
    • 基礎鞏固——至少需要多少行代碼才能實現深度復制?
      1閱讀 0條評論 個贊
      前言深度克?。ㄉ羁截悾┮恢倍际浅?、中級前端面試中經常被問到的題目,網上介紹的實現方式也都各有千秋,大體可以概括為三種方式:JSON.stringify+JSON.parse,這個很好理解;全量判斷類……
    • 高并發服務的幾點優化經驗
      1閱讀 0條評論 個贊
      前言:如何優化高并發服務,這里指的是qps在20萬以上的在線服務,注意不是離線服務,在線服務會存在哪些挑戰呢?①無法做離線緩存,所有的數據都是實時讀的②大量的請求會打到線上服務,對于服務的響應時間要……
    • 創建Go語言最快的排序算法
      1閱讀 0條評論 個贊
      前言說到排序算法,很多同學會想起快速排序、堆排序、冒泡排序這些耳熟能詳的算法。了解得深一些的同學,也可能看過例如Python的timsort以及C++introsort之類的排序算法?!?/div>
    • 在Linux中檢查磁盤空間的12個有用的df命令
      1閱讀 0條評論 個贊
      1.檢查文件系統磁盤空間使用情況這df命令顯示文件系統上的設備名稱、總塊數、總磁盤空間、已用磁盤空間、可用磁盤空間和掛載點信息。[root@local~]#dfFilesystem1K-bloc……
    最近發布資訊
    更多
    本地特级毛片,老师脱裙子让我看内裤,人妻av乱片aV出轨avApp
    <table id="qs2qo"></table>
  • <bdo id="qs2qo"><center id="qs2qo"></center></bdo>
  • <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>