我有以下代码试图遍历一个大表(~100k行; ~30GB)
def updateEmailsInLoop(cursor=None, stats={}):
BATCH_SIZE=10
try:
rawEmails, next_cursor, more = RawEmailModel.query().fetch_page(BATCH_SIZE, start_cursor=cursor)
for index, rawEmail in enumerate(rawEmails):
stats = process_stats(rawEmail, stats)
i = 0
while more and next_cursor:
rawEmails, next_cursor, more = RawEmailModel.query().fetch_page(BATCH_SIZE, start_cursor=next_cursor)
for index, rawEmail in enumerate(rawEmails):
stats = process_stats(rawEmail, stats)
i = (i + 1) %100
if i == 99:
logging.info("foobar: Finished 100 more %s", str(stats))
write_stats(stats)
except DeadlineExceededError:
logging.info("foobar: Deadline exceeded")
for index, rawEmail in enumerate(rawEmails[index:], start=index):
stats = process_stats(rawEmail, stats)
if more and next_cursor:
deferred.defer(updateEmailsInLoop, cursor = next_cursor, stats=stats, _queue="adminStats")
但是,我一直收到以下错误:
在处理此请求时,发现处理此请求的进程使用了太多内存并被终止。这可能会导致新进程用于您的应用程序的下一个请求。如果经常看到此消息,则可能是应用程序中存在内存泄漏。
......有时......
在为9个请求提供服务后,超过128 MB的软私有内存限制(154 MB)
我已经更改了我的代码,所以在任何给定时间我总是只拉入10个条目,所以我不知道为什么我的内存不足?
答案 0 :(得分:0)
有三种方法可以完成这种工作(在数据存储区中对大量行进行迭代):
对于我需要的大多数应用程序,x通常在100-500之间。 这是我用于迭代超过1.5m-2m行的代码,以生成一些报告或更新我的数据库中的内容。对于报告,我保存包含csv格式所需信息的实体,最后,我读取所有实体,合并它们并删除它们。 (这样做可以生成1.5m行的excel数据) (这是java,但应该很容易翻译成python):
resp.getWriter().println("<html><head>");
resp.getWriter().println(
"<script type='text/javascript'>function f(){window.location.href='/do/convert/" + this.getClass().getSimpleName() + "?cursor=" + cursorString + "&count="
+ count + "';}</script>");
resp.getWriter().println("</head><body onload='f()'>");
resp.getWriter().println(
"<a href='/do/convert/" + this.getClass().getSimpleName() + "?cursor=" + cursorString + "&count=" + count + "'>Next page -->" + cursorString + " </a>");
resp.getWriter().println("</body></html>");
如果您的“进度”很大且很混乱,请将其保存在实体中(一个或多个,取决于您正在做什么) 如果您正在执行任务版本,我建议您使用任务名称或使您的任务具有幂等性(特别是如果您的计数内容)。 如果你的计数东西,我建议保存包含你正在计数的实体的密钥的实体,最后计算那些。