進程池、線程池效率測試

之前我們分別對計算密集型和IO密集型任務,測試過多線程對運行效率的改進,下面我們依然分計算密集、文件讀寫、網路請求三個部分,測試使用線程池、進程池如何改進運行效率

首先導入庫並定義三種任務的函數

import requestsfrom bs4 import BeautifulSoupimport timeimport numpy as npfrom multiprocessing.dummy import Pool as ThreadPoolfrom multiprocessing import Pool# 計算從1加到50000000def cal(a = None): # 參數i沒用,只是為了和後面統一 s = 0 for i in range(50000000): s = s + i# 5000000次寫入文件def file(a = None): # 參數i沒用,只是為了和後面統一 with open(try.txt, w) as f: for i in range(5000000): f.write(abcd
)# 抓取豆瓣top250的10個網頁def gettitle(a): url = https://movie.douban.com/top250?start={}&filter=.format(a*25) r = requests.get(url) soup = BeautifulSoup(r.content, html.parser) lis = soup.find(ol, class_=grid_view).find_all(li) for li in lis: title = li.find(span, class_="title").text print(title)

下面定義線性計算、多線程、多進程的函數

# 分別將上面三個函數傳入,計算10次,返回正常循環的運行總時間def nothing(func): t = time.time() for i in range(10): func(i) duration = time.time() - t return duration# 分別將上面三個函數傳入,計算10次,返回使用多線程的運行總時間def thread(func): t = time.time() pool = ThreadPool(4) pool.map(func, range(10)) duration = time.time() - t return duration# # 分別將上面三個函數傳入,計算10次,返回使用多進程的運行總時間def process(func): t = time.time() pool = Pool(4) pool.map(func, range(10)) duration = time.time() - t return duration

下面定義計算運行時間的函數

def get_duration(curr, func): l = [] for _ in range(5): l.append(curr(func)) mean_duration = %.2f % np.mean(l) all_duration = [%.2f % i for i in l] return mean_duration, all_duration

下面運行代碼計算時間

if __name__ == __main__: # CPU密集任務對比 print(get_duration(nothing, cal)) print(get_duration(thread, cal)) print(get_duration(process, cal)) # 文件讀寫任務對比 print(get_duration(nothing, file)) print(get_duration(thread, file)) print(get_duration(process, file)) # 網路請求任務對比 print(get_duration(nothing, gettitle)) print(get_duration(thread, gettitle)) print(get_duration(process, gettitle))

結果如下

------CPU密集型任務運行時間-------線性運算(39.98, [39.57, 39.36, 40.53, 40.09, 40.35])多線程(38.31, [39.07, 37.96, 38.07, 38.31, 38.13])多進程(27.43, [27.58, 27.11, 27.82, 27.53, 27.11])------文件讀寫任務運行時間-------線性運算(54.11, [53.54, 53.96, 54.46, 53.54, 55.03])多線程(53.86, [55.44, 54.12, 52.48, 53.17, 54.08])多進程(34.98, [35.14, 34.35, 35.27, 35.20, 34.94])------網路請求任務運行時間-------線性運算(4.77, [4.74, 4.70, 4.77, 4.91, 4.72])多線程(1.96, [1.88, 2.09, 1.91, 2.04, 1.91])多進程(3.79, [3.55, 3.70, 3.50, 3.92, 4.30])

分析如下

  • 首先,CPU密集型運算。多線程無法改善運行效率,多進程可以改善。因為多進程能夠利用計算機的多核優勢,調用了更多資源進行計算
  • 在進行CPU密集運算時,可以監測任務管理器,發現在線性運算和多線程時,CPU利用率連一半都不到;而在多進程時就跑滿了所有的CPU
  • 注意一點:這裡使用線程池(進程池)都只開了4個線程(進程),因為在我的計算機上,用4個進程可以最大化利用CPU的計算能力,開更多進程也無法在計算密集型任務運行上有更大的優勢,反而會增加進程創建和切換的時間。
  • 其次,文件讀寫任務。上面結果顯示只有多進程對運行效率有所改善。
  • 其實文件讀寫任務有時候多線程也是可以改善效率的,是在打開文件、讀寫文件比較慢的時候,而上面展示的可能因為文件比較小,讀入內容比較少,所以耗費的時間基本在於操作頻繁,還是CPU負載問題,所以多線程無法提高運行效率
  • 如果讀寫文件是與資料庫連接,等待的時間就會長一些,這時多線程也能發揮更大的優勢
  • 為了更好地展現多線程在文件讀寫方面的優勢,我又進行了下面測試

file函數改為(即每次寫入內容增多)

# 500次寫入文件def file(a = None): # 參數i沒用,只是為了和後面統一 for i in range(500): with open(try.txt, w) as f: f.write(abcd*100000 +
)

運行結果如下

線性運算(55.15, [49.96, 55.75, 45.11, 52.16, 72.75])多線程(26.57, [26.67, 23.89, 25.48, 32.84, 23.94])多進程(25.72, [24.10, 25.82, 24.13, 28.03, 26.50])

可以看出這種情況下,多線程對效率的改善程度和多進程差不多。

  • 再次,網路請求任務。上面結果顯示多線程對這種任務的效率改善最為明顯,多進程也有些許改善。
  • 因為網路請求任務最主要的時間消耗在於等待網頁的回復,這時如果能同時等待多個網頁的回復,就能極大提高運行效率,多線程在此可以完美髮揮作用。
  • 最後注意一點,使用多進程時,創建進程時間開銷非常大,所以上面代碼只有通過提高函數運行時間來、才能展示多進程的優勢。網路請求任務多進程沒有改善很多的原因也正在於此。而創建多線程則輕鬆很多。
  • 結論:CPU密集任務一般用多進程提高運行效率,網路請求任務一般用多線程提高運行效率,文件讀寫看主要是CPU計算耗時還是等待耗時。

專欄信息

專欄主頁:python編程

專欄目錄:目錄

版本說明:軟體及包版本說明

推薦閱讀:

淺談操作系統-進程與線程
windows的進程和線程1--基本的概念

TAG:Python | 進程 | Python入門 |