[英]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.