[英]Script suddenly using all RAM
我有一個 python 腳本,用於將一些格式非常密集的 csv 文件轉換為我需要的另一種格式。 csv 文件非常大(3GB),所以我分塊讀取它們以避免使用所有 RAM(我正在使用的機器上有 32GB 的 RAM)。
奇怪的是,腳本使用幾 GB 的內存(根據 top 所說的大約 3GB)處理一個文件。
我完成該文件並加載下一個文件,再次分塊。 突然我使用 25GB,寫入交換,進程被殺死。 我不確定第一次和第二次迭代之間發生了什么變化。 我已經放入了一個 os.sleep(60) 試圖讓垃圾收集器趕上來,但它仍然從 ~10% 的內存到 ~85% 到終止進程。
這是腳本的主要部分:
for file in files:
sleep(60)
print(file)
read_names = True
count = 0
for df in pd.read_csv(file, encoding= 'unicode_escape', chunksize=1e4, names=['all']):
start_index = 0
count += 1
if read_names:
names = df.iloc[0,:].apply(lambda x: x.split(';')).values[0]
names = names[1:]
start_index = 2
read_names = False
for row in df.iloc[start_index:,:].iterrows():
data = row[1]
data_list = data['all'].split(';')
date_time = data_list[0]
values = data_list[1:]
date, time = date_time.split(' ')
dd, mm, yyyy = date.split('/')
date = yyyy + '/' + mm + '/' + dd
for name, value in zip(names, values):
try:
data_dict[name].append([name, date, time, float(value)])
except:
pass
if count % 5 == 0:
for name in names:
start_date = data_dict[name][0][1]
start_time = data_dict[name][0][2]
end_date = data_dict[name][-1][1]
end_time = data_dict[name][-1][2]
start_dt = start_date + ' ' + start_time
end_dt = end_date + ' ' + end_time
dt_index = pd.date_range(start=start_dt, freq='1S', periods=len(data_dict[name]))
df = pd.DataFrame(data_dict[name], index=dt_index)
df = df[3].resample('1T').mean().round(10)
with open(csv_dict[name], 'a') as ff:
for index, value in zip(df.index, df.values):
date, time = str(index).split(' ')
to_write = f"{name}, {date}, {time}, {value}\n"
ff.write(to_write)
我能做些什么來更好地管理這個問題嗎? 我需要為這個任務循環超過 50 個大文件。
數據格式:輸入
time sensor1 sensor2 sensor3 sensor....
2022-07-01 00:00:00; 2.559;.234;0;0;0;.....
2022-07-01 00:00:01; 2.560;.331;0;0;0;.....
2022-07-01 00:00:02; 2.558;.258;0;0;0;.....
輸出
sensor1, 2019-05-13, 05:58:00, 2.559
sensor1, 2019-05-13, 05:59:00, 2.560
sensor1, 2019-05-13, 06:00:00, 2.558
編輯:有趣的發現 - 我正在寫入的文件突然沒有被更新,如果寫入正常發生,它們應該在幾分鍾后。 當我檢查文件的尾部時,文件中的數據也沒有改變。 因此,我假設數據正在字典中積累並淹沒 RAM,這是有道理的。 現在要了解為什么寫作沒有發生。
編輯 2:更有趣的發現!! 該腳本在填滿 RAM 並崩潰之前運行良好的第一個 csv 和第二個 csv 的一大塊。 似乎 ram 問題從第二個文件開始,所以我跳過了處理那個文件,並且神奇地我運行的時間比到目前為止沒有內存問題的時間長。 這可能是破壞了某些東西的損壞數據。
給定file.csv
看起來完全像:
time sensor1 sensor2 sensor3 sensor4 sensor5
2022-07-01 00:00:00; 2.559;.234;0;0;0
2022-07-01 00:00:01; 2.560;.331;0;0;0
2022-07-01 00:00:02; 2.558;.258;0;0;0
你做的遠不止這些,不使用正確的pandas
方法會按時殺死你( iterrows
基本上從來都不是最好的選擇)。 基本上,如果你手動循環一個 DataFrame,你可能做錯了。
但是,如果您遵循這種將其用作上下文管理器的模式,而不是將其視為迭代器(這是一種已棄用的方法),您將不會遇到內存問題。
files = ['file.csv']
for file in files:
with open(file) as f:
# Grab the columns:
cols = f.readline().split()
# Initialize the context-manager:
# You'll want a larger chunksize, 1e5 should even work.
with pd.read_csv(f, names=cols, sep=';', chunksize=1) as chunks:
for df in chunks:
df[['date', 'time']] = df.time.str.split(expand=True)
df = df.melt(['date', 'time'], var_name='sensor')
df = df[['sensor', 'date', 'time', 'value']]
df.to_csv(f'new_{file}', mode='a', index=False, header=False)
new_file.csv
的輸出:
sensor1,2022-07-01,00:00:00,2.559
sensor2,2022-07-01,00:00:00,0.234
sensor3,2022-07-01,00:00:00,0.0
sensor4,2022-07-01,00:00:00,0.0
sensor5,2022-07-01,00:00:00,0.0
sensor1,2022-07-01,00:00:01,2.56
sensor2,2022-07-01,00:00:01,0.331
sensor3,2022-07-01,00:00:01,0.0
sensor4,2022-07-01,00:00:01,0.0
sensor5,2022-07-01,00:00:01,0.0
sensor1,2022-07-01,00:00:02,2.558
sensor2,2022-07-01,00:00:02,0.258
sensor3,2022-07-01,00:00:02,0.0
sensor4,2022-07-01,00:00:02,0.0
sensor5,2022-07-01,00:00:02,0.0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.