我正在使用实验性blobstore文件API来编写包含某些事件数据的CSV文件。有很多数据所以我正在批量写入。我的代码在后端运行,所以我有很多时间,但我的内存不足,我不明白为什么。
以下是代码:
from __future__ import with_statement
from google.appengine.api import files
q = Event.all()
events = q.fetch(50)
while events:
with files.open(blobname, 'a') as f:
buf = StringIO()
for event in events:
buf.write(event.id)
buf.write(',')
buf.write(`event.logged`)
buf.write(',')
buf.write(event.type)
buf.write(',')
buf.write(event.timestamp)
buf.write(',')
needAmpersand = False
for prop in event.dynamic_properties():
if needAmpersand:
buf.write('&')
needAmpersand = True
buf.write(prop + '=' + str(getattr(event, prop)))
buf.write('\n')
f.write(buf.getvalue())
buf.close()
events = q.fetch(50)
files.finalize(blobname)
此代码使while循环事件循环大约20次,然后进程中止耗尽了超过140 mb的内存。 Event是特定于此应用程序的数据库模型。事件基本上是远程计算机上发生的事情的记录,稍后这些事件将通过map reduce操作来处理以构建统计信息,现在我只想下载它们。我们的数据库中有100个事件中有100个(稍后我们也会切换到以不同方式存储它们,但现在就是这样)。
我注意到with f.open
每次完成with子句时都会调用f.close
,因为f.close()
调用了f.__exit__()
此代码的早期实例化仅在写入'StringIO'的每个元素上调用f.write(..)。这个早期版本的内存耗尽得更快,但其他方面表现相似。这段代码还有一些东西会导致内存泄漏。
帮助?
更新 我刚刚尝试注释掉f.write(buf.getvalue()),虽然它显然没有创建一个包含任何内容的blobstore项,但它最终完成了处理所有Event实体。我错过了什么或f.write()泄漏内存或缓冲所有内容,直到finalize()?
答案 0 :(得分:1)
当你致电f.write(buf.getvalue())
时,你要求StringIO
将自己变成一个内存对象并传递它。这将是昂贵的。
尝试buf.seek(0)
,它将回退到流的开头,然后只传递f.write(buf)
。 StringIO
是一个类似文件的对象,f.write
应该能够将其作为流读取。
查看source,从文档或代码中不清楚file_service_pb.AppendRequest
是否可以处理StringIO。试试吧。