【问题标题】:How can I release memory after using csv.writer in python?在 python 中使用 csv.writer 后如何释放内存?
【发布时间】:2016-08-18 18:45:15
【问题描述】:

我有 1.6GB 可用于 python 进程。我正在编写一个大型 csv 文件,其中数据来自数据库。问题是:文件写入后,内存(>1.5GB)没有立即释放,导致下一段代码出错(分配内存失败,因为操作系统找不到足够的内存分配)。

是否存在任何可以帮助我释放内存的函数? 或者,您有更好的方法吗?

这是我用来写入文件的脚本,正在分块写入以处理内存问题:

size_to_read = 20000
sqlData = rs_cursor.fetchmany(size_to_read)

c = csv.writer(open(fname_location, "wb"))
c.writerow(headers)

print("- Generating file %s ..." % out_fname)

while sqlData:
  for row in sqlData:
     c.writerow(row)
  sqlData = rs_cursor.fetchmany(size_to_read)

【问题讨论】:

  • 最后一行之后出错的代码吗?还是它出错的最后一行?
  • 不,它使用低内存占用了数百行,错误出现在这一行:file_obs = int(subprocess.check_output(["cat %s/%s | wc -l" % (locationToUpload, 文件名)], shell=True))
  • 我可能会误解,但... sqlData = rs_cursor.fetchmany(size_to_read) 在最后一行?您刚刚写入文件的所有内容(您尚未关闭),您再次加载它吗?
  • 您的缩进已关闭。请修复以匹配您的实际代码,因为您有多个循环,我们无法确定一些何时终止
  • 听起来内存可能正在用于文件上的缓冲区或 csv.writer 使用的对象。您可以通过在上面的代码之后添加del c 来测试它,这应该会提示 Python 恢复 c 使用的内存并关闭仅由 c 引用的文件句柄。一般来说,最好保留文件的句柄,然后在完成后显式关闭它。见stackoverflow.com/questions/3347775/csv-writer-not-closing-file

标签: python csv


【解决方案1】:

我认为问题在于您从未关闭过文件。试一试。

size_to_read = 20000
sqlData = rs_cursor.fetchmany(size_to_read)

with open(fname_location, "wb")) as f:
    c = csv.writer(f)
    c.writerow(headers)

print("- Generating file %s ..." % out_fname)

while sqlData:
    with open(fname_location, "a") as f: # "a" means to append
        c = csv.writer(f)
        for row in sqlData:
            c.writerow(row)
    sqlData = rs_cursor.fetchmany(size_to_read)

使用with 可以自动关闭文件并释放内存。避免了显式调用c.close()

另外我相信你可以通过这样的方式避免循环......

while sqlData:
    with open(fname_location, "wb") as f:
        c = csv.writer(f)
        c.writerows(sqlData) # .writerows
    sqlData = rs_cursor.fetchmany(size_to_read)

因为我没有数据,所以很难复制 :(

编辑

我知道这不是一个真正的答案,但请查看包 memory_profiler 进行逐行评估,看看您在哪里使用了大量内存。 https://pypi.python.org/pypi/memory_profiler

编辑 2

这是一个使用生成器来降低内存使用率的示例。

def results_iter(cursor, n=10000):
    while True:
        results = cursor.fetchmany(n)
        if not results:
            break
        for result in results:
            yield result

with open('file.csv') as f:
    c = csv.writer(f)
    for result in results_iter(rs_cursor, size_to_read)
        c.writerow(result)

通过http://code.activestate.com/recipes/137270-use-generators-for-fetching-large-db-record-sets/

如果其中任何一项有效,请告诉我们!

【讨论】:

  • 是的,我真的不知道可能就像我说的不知道数据是什么样子的。或者他所说的size_to_read 是什么意思。但感谢您的反对!
  • 我会说在中间的事件操作中反复打开它(即获取更多数据)占用大量内存并使应用程序崩溃。但是是的,循环的范围令人困惑。发布错误的东西确实有价值,因为人们可能会挑出你没有想到的问题。
  • 基本上,我正在使用循环,因为没有它,系统将在写入文件时耗尽内存。所以,我的想法是在全部完成后写入数据块。 size_to_read 是进程为每个循环写入的行数。
  • @ebertbm 请更新问题,以便集中相关信息。 sry rogan 也没有看到。
  • c.writerows(row) 应该是c.writerows(sqlData)。此外,with csv.writer(...) as c: 可能会自动关闭文件,但这只是垃圾收集的副作用,当c 被新的c 替换时(此时,旧的c 持有对文件句柄,所以文件句柄也会被收集,这应该会导致它被关闭)。最好从with open(...) as f: 开始,然后是c = csv.writer(f)。见stackoverflow.com/questions/3347775/csv-writer-not-closing-file
猜你喜欢
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-05
  • 2019-11-14
相关资源
最近更新 更多