2017-01-16 28 views
1

我有大量的數據文件,並且從數據文件加載的每個數據都被重新採樣數百次,並通過多種方法進行處理。我用numpy來做到這一點。我所面對的是運行程序幾個小時後的內存錯誤。由於每個數據分開處理,並將結果保存在一個文件.mat使用scipy.savemat,我認爲以前的數據所使用的內存可以被釋放,所以我用del variable_name + gc.collect(),但這不起作用。然後我用multiprocessing模塊,如仍處於this postthis post建議,它不工作。如何在Python中有效釋放內存?

這裏是我的主要代碼:

import scipy.io as scio 
import gc 
from multiprocessing import Pool 

def dataprocess_session: 
    i = -1 
    for f in file_lists: 
     i += 1 
     data = scio.loadmat(f) 
     ixs = data['rm_ix'] # resample indices 
     del data 
     gc.collect() 
     data = scio.loadmat('xd%d.mat'%i) # this is the data, and indices in "ixs" is used to resample subdata from this data 

     j = -1 
     mvs_ls_org = {} # preallocate results files as dictionaries, as required by scipy.savemat. 
     mvs_ls_norm = {} 
     mvs_ls_auto = {} 
     for ix in ixs: 
      j += 1 
      key = 'name%d'%j 
      X = resample_from_data(data,ix) 
      mvs_ls_org[key] = process(X) 

     scio.savemat('d%d_ls_org.mat'%i,mvs_ls_org) 
     del mvs_ls_org 
     gc.collect() 

     j = -1 
     for ix in ixs: 
      j += 1 
      key = 'name%d'%j 
      X = resample_from_data(data,ix) 
      X2 = scale(X.copy(), 'norm') 
      mvs_ls_norm[key] = process(X2) 

     scio.savemat('d%d_ls_norm.mat'%i,mvs_ls_norm) 
     del mvs_ls_norm 
     gc.collect() 

     j = -1 
     for ix in ixs: 
      j += 1 
      key = 'name%d'%j 
      X = resample_from_data(data,ix) 
      X2 = scale(X.copy(), 'auto') 
      mvs_ls_auto[key] = process(X2) 

     scio.savemat('d%d_ls_auto.mat'%i,mvs_ls_auto) 
     del mvs_ls_auto 
     gc.collect() 

     # use another method to process data 
     j = -1 
     mvs_fcm_org = {} # also preallocate variable for storing results 
     mvs_fcm_norm = {} 
     mvs_fcm_auto = {} 
     for ix in ixs: 
      j += 1 
      key = 'name%d'%j 
      X = resample_from_data(data['X'].copy(), ix) 
      dp, _ = process_2(X.copy()) 
      mvs_fcm_org[key] = dp 

     scio.savemat('d%d_fcm_org.mat'%i,mvs_fcm_org) 
     del mvs_fcm_org 
     gc.collect() 

     j = -1 
     for ix in ixs: 
      j += 1 
      key = 'name%d'%j 
      X = resample_from_data(data['X'].copy(), ix) 
      X2 = scale(X.copy(), 'norm') 
      dp, _ = process_2(X2.copy()) 
      mvs_fcm_norm[key] = dp 

     scio.savemat('d%d_fcm_norm.mat'%i,mvs_fcm_norm) 
     del mvs_fcm_norm 
     gc.collect() 

     j = -1 
     for ix in ixs: 
      j += 1 
      key = 'name%d'%j 
      X = resample_from_data(data['X'].copy(), ix) 
      X2 = scale(X.copy(), 'auto') 
      dp, _ = process_2(X2.copy()) 
      mvs_fcm_auto[key] = dp 

     scio.savemat('d%d_fcm_auto.mat'%i,mvs_fcm_auto) 
     del mvs_fcm_auto 
     gc.collect() 

這是最初的方式,我已經做到了。我將file_lists分成7部分,並運行7個python屏幕,因爲我的電腦有8個CPU核心。 如果我這樣做,MATLAB中沒有問題。我不超過ixs結合迭代每個數據處理方法,因爲可能會出現內存不足的錯誤,所以我跑resample_from_data並單獨保存的結果。由於內存錯誤仍然存​​在,我用Pool類爲:

pool = Pool(processes=7) 
pool.map(dataprocess_session_2, file_lists) 

跑在file_lists文件名作爲輸入並行過file_lists迭代。

所有代碼在openSuSE中運行,其中python 2.7.58 cores CPU32G RAM。我用top來監視使用的內存。所有的矩陣都不是很大,如果我使用所有代碼運行任何一個加載的數據,那也沒關係。但經過file_lists的多次迭代後,可用內存急劇下降。我確信這種現象不是由數據本身引起的,因爲即使是最大的數據矩陣處理中也不應該使用這樣大的存儲器。所以我懷疑上述的方式我試圖釋放處理以前的數據使用的內存以及存儲處理結果並沒有真正釋放內存。

有什麼建議嗎?

+0

爲什麼我被低估了? – Elkan

+0

我真的需要自己仔細閱讀這篇文章,但我認爲你不能用這種方式強迫'gc'的手。 Python使用引用計數來決定是否刪除對象,所以'gc.collect()'可能不會立即刪除這些對象。如果你想把每個循環分解成不返回數據的函數,你可能會有更多的希望,但是你應該只是把這個作爲一個輔助手段來進一步閱讀python gc,因爲我可以做得更好那個建議。希望有更多的知識能夠澄清。 – roganjosh

+0

更新你的建議:我現在正在嘗試,雖然沒有發生錯誤,但是在運行這兩天的數據集後,只剩幾KB的內存(與我的PC的32G RAM相比)是空閒的。由於處理的數據體積相對較小,恐怕如果以這種方式使用,內存仍然可能會耗盡。 – Elkan

回答

-3

這可能是一些幫助,所以GC.Collect()

+1

「我認爲先前數據使用的內存可以釋放,所以我使用了del variable_name + gc.collect(),但這不起作用。」 – roganjosh

0

del明確被立即自動循環結束髮布的所有變量。隨後我不認爲他們是你的問題。我認爲你的機器很可能無法處理7個線程(在最壞的情況下)7同時執行data = scio.loadmat(f)。您可以嘗試將該呼叫標記爲帶鎖的關鍵部分。

+0

謝謝。你能解釋一下嗎?將7個數據同時加載到內存中沒有問題,那麼「機器無​​法處理7個線程並同時執行data = scio.loadmat(f)」是什麼意思? – Elkan

+0

這不僅僅是7個數據。您需要考慮最糟糕的情況,即所有線程正在使用其最大內存量。我無法告訴你哪些對象最大,你可能能夠對它們進行分析(最好是單線程模式)。 –

+0

我明白了。我使用MATLAB對同樣的數據集做了相同的工作,但是使用了不同的處理方法,這些方法在我的python代碼中由'process'函數指定,甚至在MATLAB中加載到內存中,運行數天後沒有錯誤存在。由於我的矩陣不是很大,返回的'X'和'X2'與原始矩陣具有相同的大小,並且即使在通過'ixs'迭代之後仍然具有大的可用空間。這是由linux中的'top'監控的。我注意到python仍然在'del'後面保留'free lists',但是我沒有找到任何有效的解決方案。所以我懷疑我是否錯過了一些東西。 – Elkan