繁体   English   中英

Python Pandas 内存泄漏?

[英]Python Pandas leaking memory?

我有一个脚本,它不断测量一些数据并定期将其存储在一个文件中。 过去,我以这种方式(伪代码)将数据存储在“手动创建的 CSV”文件中:

with open('data.csv','w') as ofile:
    print('var1,var2,var3,...,varN', file=ofile) # Create CSV header.
    while measure:
        do_something()
        print(f'{var1},{var2},{var3},...,{varN}', file=ofile) # Store data.

我以这种方式工作了几个月并运行了这个脚本数百次,除了 1)当 N 很大(在我的情况下在 20 到 30 之间)和 2)CSV 时,这很麻烦(并且容易出错)不保留数据类型。 所以我决定改成这样:

temporary_df = pandas.DataFrame()
while measure:
    do_something()
    temporary_df.append({'var1':var1,'var2':var2,...,'varN':varN}, ignore_index=True)
    if save_data_in_this_iteration():
        temporary_df.to_feather(f'file_{datetime.datetime.now()}.fd')
        temporary_df = pandas.DataFrame() # Clean the dataframe.
merge_all_feathers_into_single_feather()

乍一看,这和我预期的一样完美。 然而,几个小时后 Python 崩溃了。 在 Windows 和(单独的)Linux 机器 I 中经历过这种情况后,我注意到问题是 Python 正在缓慢地吸取机器的内存,直到没有更多内存,然后当然会崩溃。

由于功能do_something是不变的两种方法,以及碰撞发生之前merge_all_feathers_into_single_feather被调用, save_data_in_this_iteration是平凡简单,我指责大熊猫这个问题。

谷歌告诉我,过去其他人在使用 Pandas 时遇到过记忆问题。 我已经尝试在每次迭代中添加垃圾收集器行,如建议例如此处,但对我不起作用。 我还没有尝试多处理方法,因为它看起来像用核武器杀死一只蚂蚁,并且可能会带来其他并发症......

有没有什么解决方案可以像这样继续使用 Pandas? 不使用 Pandas 有没有更好的解决方案? 哪一个?

熊猫不是问题

在解决这个问题一段时间后,我决定创建一个 MWE 来做一些测试。 所以我写了这个:

import pandas
import numpy
import datetime

df = pandas.DataFrame()
while True:
    df = df.append({f'col_{i}': numpy.random.rand() for i in range(99)}, ignore_index=True)
    if 'last_clean' not in locals() or (datetime.datetime.now()-last_clean).seconds > .5:
        last_clean = datetime.datetime.now()
        df.to_feather('delete_me.fd')
        df = df[0:0]

令我惊讶的是,这个脚本并没有耗尽内存! 所以在这里我得出结论,Pandas 不是我的问题。

然后我向 MWE 添加了一个新组件,我发现了问题:

import pandas
import numpy
import datetime
import matplotlib.pyplot as plt

def save_matplotlib_plot(df):
    fig, ax = plt.subplots()
    ax.plot(df['col_1'], df['col_2'])
    fig.savefig('delete_me.png')
    # Uncomment the following two lines to release the memory and stop the "leak".
    # ~ fig.clear()
    # ~ plt.close(fig)

df = pandas.DataFrame()
while True:
    df = df.append({f'col_{i}': numpy.random.rand() for i in range(99)}, ignore_index=True)
    if 'last_clean' not in locals() or (datetime.datetime.now()-last_clean).seconds > .5:
        last_clean = datetime.datetime.now()
        df.to_feather('delete_me.fd')
        save_matplotlib_plot(df) # Here I had my "leak" (which was not a leak indeed because matplotlib keeps track of all the figures it creates, so it was working as expected).
        df = df[0:0]

似乎当我从“手工制作的 CSV”切换到“Pandas”时,我也对情节进行了一些更改,因此当它不是问题时,我将其归咎于 Pandas。

只是为了完整性,多处理解决方案也有效。 以下脚本没有内存问题:

import pandas
import numpy
import datetime
import matplotlib.pyplot as plt
from multiprocessing import Process

def save_matplotlib_plot(df):
    fig, ax = plt.subplots()
    ax.plot(df['col_1'], df['col_2'])
    fig.savefig('delete_me.png')

df = pandas.DataFrame()
while True:
    df = df.append({f'col_{i}': numpy.random.rand() for i in range(99)}, ignore_index=True)
    if 'last_clean' not in locals() or (datetime.datetime.now()-last_clean).seconds > .5:
        last_clean = datetime.datetime.now()
        df.to_feather('delete_me.fd')
        p = Process(target=save_matplotlib_plot, args=(df,))
        p.start()
        p.join()
        df = df[0:0]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM