本文首發於知乎
以前咱們分別對計算密集型和IO密集型任務,測試過多線程對運行效率的改進,下面咱們依然分計算密集、文件讀寫、網絡請求三個部分,測試使用線程池、進程池如何改進運行效率html
首先導入庫並定義三種任務的函數python
import requests
from bs4 import BeautifulSoup
import time
import numpy as np
from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing import Pool
# 計算從1加到50000000
def 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\n')
# 抓取豆瓣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
複製代碼
下面運行代碼計算時間bash
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密集型運算。多線程沒法改善運行效率,多進程能夠改善。由於多進程可以利用計算機的多核優點,調用了更多資源進行計算app
在進行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 + '\n')
複製代碼
運行結果以下
線性運算
('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編程
專欄目錄:目錄
版本說明:軟件及包版本說明