使用Python實(shí)現(xiàn)多線程和多處理方法
在本教程中,我們將學(xué)習(xí)如何使用Python實(shí)現(xiàn)多線程和多處理方法。這些方法指導(dǎo)操作系統(tǒng)優(yōu)化使用系統(tǒng)硬件,從而提高代碼執(zhí)行效率。多線程引用Wiki的解釋—在計(jì)算機(jī)體系結(jié)構(gòu)中,多線程是指從軟件或者硬件上實(shí)現(xiàn)多個(gè)線程并發(fā)執(zhí)行的技術(shù)。具有多線程能力的計(jì)算機(jī)因有硬件支持而能夠在同一時(shí)間執(zhí)行多個(gè)線程,進(jìn)而提升整體處理性能。并發(fā)指的是可以實(shí)現(xiàn)多個(gè)進(jìn)程的并行執(zhí)行,從而實(shí)現(xiàn)更快的運(yùn)行時(shí)間。當(dāng)執(zhí)行基于I/O的任務(wù)(如下載圖像和文件)時(shí),多線程是更有效的,另一方面多處理也適合于基于CPU的計(jì)算密集型任務(wù)。Python中的多線程實(shí)現(xiàn)為了實(shí)現(xiàn)多線程,我們將使用Python的標(biāo)準(zhǔn)庫(kù)threading。默認(rèn)情況下,該庫(kù)Python會(huì)默認(rèn)安裝,因此可以直接在代碼中導(dǎo)入。為了演示多線程的有效性,我們將從Unsplash下載5幅圖像。讓我們觀察一下當(dāng)我們按順序下載這些圖像時(shí)的執(zhí)行時(shí)間:#### 導(dǎo)入請(qǐng)求庫(kù)import requests
#### 定義函數(shù)def down_img(name,link): data = requests.get(link).content name = f"/home/isud/DidYouKnow/Tutorial 5/{name}.jpg" with open(name, "wb") as file: file.write(data)
#### 連續(xù)下載5張圖片%%timeit -n1 -r1images = ['https://images.unsplash.com/photo-1531458999205-f31f14fa217b', 'https://images.unsplash.com/photo-1488572749058-7f52dd70e0fa', 'https://images.unsplash.com/photo-1531404610614-68f9e73e35db', 'https://images.unsplash.com/photo-1523489405193-3884f5ca475f', 'https://images.unsplash.com/photo-1565098735462-5db3412ac4cb']for i,link in enumerate(images): down_img(i,link)
#### %%timeit results51.4 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)可以觀察到,5張圖片的完整下載耗時(shí)51.4秒,而且只有在上一次下載結(jié)束后才開始新的下載,F(xiàn)在讓我們看看多線程如何提高代碼性能。#### 導(dǎo)入必要的庫(kù)import threadingimport requests
#### 定義函數(shù)def down_img(name,link): data = requests.get(link).content name = f"/home/isud/DidYouKnow/Tutorial 5/{name}.jpg" with open(name, "wb") as file: file.write(data)
#### 并行線程下載圖像%%timeit -n1 -r1threads = []images = ['https://images.unsplash.com/photo-1531458999205-f31f14fa217b', 'https://images.unsplash.com/photo-1488572749058-7f52dd70e0fa', 'https://images.unsplash.com/photo-1531404610614-68f9e73e35db', 'https://images.unsplash.com/photo-1523489405193-3884f5ca475f', 'https://images.unsplash.com/photo-1565098735462-5db3412ac4cb']for i,link in enumerate(images): t = threading.Thread(target=down_img, args=(i,link)) t.start() threads.a(chǎn)ppend(t)
for thread in threads: thread.join()
#### %%timeit results25.6 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)代碼解釋-定義圖像下載循環(huán):第1步(線程初始化)——Python在一個(gè)線程中運(yùn)行完整的代碼(我們稱之為主線程)。在本例中,通過從線程庫(kù)調(diào)用Thread函數(shù),我們啟動(dòng)并行線程并為它們分配一個(gè)要執(zhí)行的目標(biāo)進(jìn)程(在本例中為down_image)。被調(diào)用函數(shù)所需的所有參數(shù)都應(yīng)作為序列對(duì)象(在本例中為元組)傳遞。對(duì)Thread函數(shù)的每次調(diào)用都會(huì)啟動(dòng)一個(gè)新線程(我們稱之為并行線程)。第2步(線程啟動(dòng))——調(diào)用線程的start方法將指示Python啟動(dòng)線程執(zhí)行。如果for循環(huán)在主線程中執(zhí)行,而函數(shù)調(diào)用在并行線程中,則for循環(huán)的執(zhí)行將在圖片下載過程中繼續(xù)執(zhí)行。步驟3(線程的join)——每個(gè)新線程都被捕獲到一個(gè)名為threads的列表中,然后通過調(diào)用join方法將并行線程連接到主線程。為什么需要使用join?在第2步之前,我們所有的線程(主線程和并行線程)都是并行執(zhí)行的,在這種情況下,主線程完成任務(wù)的時(shí)間可以比并行線程完成任務(wù)早很多,及主線程會(huì)結(jié)束更早。為了避免這種情況,將并行線程連接到主線程是必須的,這將確保只有在并行線程完成之后才完成主線程的執(zhí)行。下圖說明了這兩種情況:
可以看出,下載圖像的執(zhí)行時(shí)間減少了近50%(大約25.6秒)。上面的示例展示了多線程在I/O操作中的幫助,以及如何提高下載/上傳過程的效率。多處理與在單個(gè)進(jìn)程中執(zhí)行多個(gè)線程的多線程不同,多處理為每個(gè)任務(wù)啟動(dòng)一個(gè)新的并行進(jìn)程。如前所述,它為CPU密集型任務(wù)(需要大量計(jì)算的任務(wù))提供了相當(dāng)大的運(yùn)行時(shí)改進(jìn)。在Python中實(shí)現(xiàn)多處理multiprocessing是另一個(gè)在Python中支持多處理特性的標(biāo)準(zhǔn)庫(kù),為了理解它的功能,我們將多次調(diào)用一個(gè)計(jì)算密集型函數(shù),來計(jì)算從1到1千萬的數(shù)字的平方。此函數(shù)并行執(zhí)行8次,讓我們觀察一下這個(gè)函數(shù)在正常情況下的性能。#### 導(dǎo)入時(shí)間庫(kù)import time
#### 定義函數(shù)def demo_func(num): for i in range(num): a = i**2
#### 順序調(diào)用演示函數(shù)%%timeit -n1 -r1for i in range(8): demo_func(10000000)
#### %%timeit 結(jié)果21.2 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)演示函數(shù)的順序執(zhí)行總共花費(fèi)了21.2秒,現(xiàn)在讓我們檢查在多處理設(shè)置中執(zhí)行此操作時(shí)的性能提升。#### 導(dǎo)入庫(kù)import time
#### 定義函數(shù)def demo_func(num): for i in range(num): a = i**2
#### 多處理demo函數(shù)%%timeit -n1 -r1processes = []lop_size = [10000000,10000000,10000000,10000000,10000000,10000000,10000000, 10000000]p = multiprocessing.Pool()p.map(demo_func,lop_size)p.close()p.join()
#### %%timeit 結(jié)果11.6 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)在多處理框架下,執(zhí)行時(shí)間減少了50%,達(dá)到11.6秒。在順序處理中,一次使用一個(gè)CPU內(nèi)核,而在多個(gè)處理中,所有系統(tǒng)內(nèi)核都是并行使用的。CPU使用率屏幕截圖顯示了相同的情況:
上圖中的每一行代表一個(gè)CPU核。請(qǐng)注意,在順序執(zhí)行中,每個(gè)函數(shù)調(diào)用都會(huì)觸發(fā)一個(gè)核,而在并行執(zhí)行中,所有核都是同時(shí)觸發(fā)的。代碼說明步驟1(池創(chuàng)建)-池方法創(chuàng)建可并行利用的進(jìn)程池。在沒有任何參數(shù)的情況下,創(chuàng)建的進(jìn)程數(shù)等于系統(tǒng)上的CPU核數(shù)。我有一個(gè)四核系統(tǒng),這意味著,在執(zhí)行時(shí)的8個(gè)函數(shù)調(diào)用中,前4個(gè)調(diào)用將并行運(yùn)行,然后是下4個(gè)函數(shù)調(diào)用。請(qǐng)注意,你還可以在池中定義一個(gè)自定義的進(jìn)程數(shù)(多于內(nèi)核數(shù)),但超過某個(gè)值時(shí),它將開始占用系統(tǒng)內(nèi)存并可能降低性能步驟2(池映射)-這是指示進(jìn)程執(zhí)行特定函數(shù)(第一個(gè)參數(shù))以及要傳遞給它的參數(shù)列表(第二個(gè)參數(shù))步驟3(Pool Close)-Close方法指示Python解釋器,我們已經(jīng)提交了要提交給池的所有內(nèi)容,將來不再向池提供更多的輸入。步驟4(池連接)-與線程的情況一樣,Join方法確保代碼執(zhí)行只在所有并行進(jìn)程完成后完成。從上面的場(chǎng)景中,我們可以看到多處理是如何在高效的代碼性能方面成為一個(gè)很好的幫手。結(jié)束本教程中,我們將重點(diǎn)放在通過優(yōu)化系統(tǒng)硬件來提高代碼性能上。希望這篇教程能幫助你,你能學(xué)到一些新東西。

發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
3月27日立即報(bào)名>> 【工程師系列】汽車電子技術(shù)在線大會(huì)
-
4月30日立即下載>> 【村田汽車】汽車E/E架構(gòu)革新中,新智能座艙挑戰(zhàn)的解決方案
-
5月15-17日立即預(yù)約>> 【線下巡回】2025年STM32峰會(huì)
-
即日-5.15立即報(bào)名>>> 【在線會(huì)議】安森美Hyperlux™ ID系列引領(lǐng)iToF技術(shù)革新
-
5月15日立即下載>> 【白皮書】精確和高效地表征3000V/20A功率器件應(yīng)用指南
-
5月16日立即參評(píng) >> 【評(píng)選啟動(dòng)】維科杯·OFweek 2025(第十屆)人工智能行業(yè)年度評(píng)選
推薦專題
- 1 UALink規(guī)范發(fā)布:挑戰(zhàn)英偉達(dá)AI統(tǒng)治的開始
- 2 北電數(shù)智主辦酒仙橋論壇,探索AI產(chǎn)業(yè)發(fā)展新路徑
- 3 降薪、加班、裁員三重暴擊,“AI四小龍”已折戟兩家
- 4 “AI寒武紀(jì)”爆發(fā)至今,五類新物種登上歷史舞臺(tái)
- 5 國(guó)產(chǎn)智駕迎戰(zhàn)特斯拉FSD,AI含量差幾何?
- 6 光計(jì)算迎來商業(yè)化突破,但落地仍需時(shí)間
- 7 東陽(yáng)光:2024年扭虧、一季度凈利大增,液冷疊加具身智能打開成長(zhǎng)空間
- 8 地平線自動(dòng)駕駛方案解讀
- 9 封殺AI“照騙”,“淘寶們”終于不忍了?
- 10 優(yōu)必選:營(yíng)收大增主靠小件,虧損繼續(xù)又逢關(guān)稅,能否乘機(jī)器人東風(fēng)翻身?