當我們有一個很長很長的任務隊列(mission_list)和閾值對應的一個處理函數(shù)(missionFunction)時,我們一般采用如下的方式進行處理:
創(chuàng)新互聯(lián)公司服務項目包括貴南網(wǎng)站建設、貴南網(wǎng)站制作、貴南網(wǎng)頁制作以及貴南網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯(lián)網(wǎng)行業(yè)的解決方案,貴南網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到貴南省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!
但是,如果這任務列表很長很長,處理函數(shù)很復雜(占用cpu)時,單核往往需要很長的時間進行處理,此時,Multiprocess便可以極大的提高我們程序的運行速度,相關內容請借鑒 multiprocessing --- 基于進程的并行 — Python 3.10.4 文檔。
以上這種場景下,推薦大家采用最簡單的進程池+map的方法進行處理,標準的寫法, chunksize要借鑒官方的說法,最好大一點 :
但是!?。?! 如果我們的任務列表非常的長,這會導致多進程還沒跑起來之前,內存已經(jīng)撐爆了,任務自然沒法完成,此時我們有幾種辦法進行優(yōu)化:
進程的啟動方法有三種,可參考官方文檔:
[圖片上傳失敗...(image-48cd3c-1650511153989)]
在linux環(huán)境下,使用forkserver可以節(jié)省很多的內存空間, 因為進程啟動的是一個服務,不會把主進程的數(shù)據(jù)全部復制
采用imap會極大的節(jié)省空間,它返回的是一個迭代器,也就是結果列表:
但注意,以上寫法中,你寫的結果迭代部分必須寫在with下面?;蛘卟捎昧硪环N寫法:
還有最后一種,當你的mission list實在太大了,導致你在生成 mission list的時候已經(jīng)把內存撐爆了,這個時候就得優(yōu)化 mission_list了,如果你的mission_list是通過一個for循環(huán)生成的,你可以使用yield字段,將其封裝為一個迭代器,傳入進程池:
這樣子,我們就封裝好了mission_list,它是一個可迭代對象,在取數(shù)據(jù)的時候才會將數(shù)據(jù)拉到內存
我在項目中結合了后兩種方法,原本256G的內存都不夠用,但在修改后內存只占用了不到10G。希望能夠幫助到你
分區(qū)表錯誤是硬盤的嚴重錯誤,不同錯誤的程度會造成不同的損失。如果是沒有活動分區(qū)標志,則計算機無法啟動。但從軟區(qū)或光區(qū)引導系統(tǒng)后可對硬盤讀寫,可通過fdisk重置活動分區(qū)進行修復。如果是某一分區(qū)類型錯誤,可造成某一分區(qū)的丟失。分區(qū)表的第四個字節(jié)為分區(qū)類型值,正常的可引導的大于32mb的基本DOS分區(qū)值為06,而擴展的DOS分區(qū)值是05。如果把基本DOS分區(qū)類型改為05則無法啟動系統(tǒng) ,并且不能讀寫其中的數(shù)據(jù)。如果把06改為DOS不識別的類型如efh,則DOS認為改分區(qū)不是 DOS分區(qū),當然無法讀寫。很多人利用此類型值實現(xiàn)單個分區(qū)的加密技術,恢復原來的正確類型值即可使該分區(qū)恢復正常。分區(qū)表中還有其他數(shù)據(jù)用于紀錄分區(qū)的起始或終止地址。這些數(shù)據(jù)的損壞將造成該分區(qū)的混亂或丟失,一般無法進行手工恢復,唯一的方法是用備份的分區(qū)表數(shù)據(jù)重新寫回,或者從其他的相同類型的并且分區(qū)狀況相同的硬盤上獲取分區(qū)表數(shù)據(jù),否則將導致其他的數(shù)據(jù)永久的丟失。在對主引導扇區(qū)進行操作時,可采用nu等工具軟件,操作非常的方便,可直接對硬盤主引導扇區(qū)進行讀寫或編輯。當然也可采用de
1. 使用裝飾器來衡量函數(shù)執(zhí)行時間
有一個簡單方法,那就是定義一個裝飾器來測量函數(shù)的執(zhí)行時間,并輸出結果:
import time
from functoolsimport wraps
import random
def fn_timer(function):
@wraps(function)
def function_timer(*args, **kwargs):
? t0= time.time()
? result= function(*args, **kwargs)
? t1= time.time()
? print("Total time running %s: %s seconds" %
? ? ? (function.__name__, str(t1- t0))
)
? return result
return function_timer
@fn_timer
def random_sort(n):
return sorted([random.random() for i in range(n)])
if __name__== "__main__":
random_sort(2000000)
輸出:Total time running random_sort: 0.6598007678985596 seconds
使用方式的話,就是在要監(jiān)控的函數(shù)定義上面加上 @fn_timer 就行了
或者
# 可監(jiān)控程序運行時間
import time
import random
def clock(func):
def wrapper(*args, **kwargs):
? ? start_time= time.time()
? ? result= func(*args, **kwargs)
? ? end_time= time.time()
? ? print("共耗時: %s秒" % round(end_time- start_time, 5))
? ? return result
return wrapper
@clock
def random_sort(n):
return sorted([random.random() for i in range(n)])
if __name__== "__main__":
random_sort(2000000)
輸出結果:共耗時: 0.65634秒
2. 使用timeit模塊
另一種方法是使用timeit模塊,用來計算平均時間消耗。
執(zhí)行下面的腳本可以運行該模塊。
這里的timing_functions是Python腳本文件名稱。
在輸出的末尾,可以看到以下結果:4?loops, best of?5:?2.08?sec per loop
這表示測試了4次,平均每次測試重復5次,最好的測試結果是2.08秒。
如果不指定測試或重復次數(shù),默認值為10次測試,每次重復5次。
3. 使用Unix系統(tǒng)中的time命令
然而,裝飾器和timeit都是基于Python的。在外部環(huán)境測試Python時,unix time實用工具就非常有用。
運行time實用工具:
輸出結果為:
Total?time running random_sort:?1.3931210041?seconds
real?1.49
user?1.40
sys?0.08
第一行來自預定義的裝飾器,其他三行為:
real表示的是執(zhí)行腳本的總時間
user表示的是執(zhí)行腳本消耗的CPU時間。
sys表示的是執(zhí)行內核函數(shù)消耗的時間。
注意:根據(jù)維基百科的定義,內核是一個計算機程序,用來管理軟件的輸入輸出,并將其翻譯成CPU和其他計算機中的電子設備能夠執(zhí)行的數(shù)據(jù)處理指令。
因此,Real執(zhí)行時間和User+Sys執(zhí)行時間的差就是消耗在輸入/輸出和系統(tǒng)執(zhí)行其他任務時消耗的時間。
4. 使用cProfile模塊
5. 使用line_profiler模塊
6. 使用memory_profiler模塊
7. 使用guppy包