加载 'too large' 数据或资源不足(CPU 或内存)时,python 的行为是什么?
What is python behavior when loading 'too large' data, or not having enough resources (either CPU or memory)?
我正在开发一个程序,该程序有时会对列表进行 for
循环,其中一些很小,一些很大(500k + 个元素)。
当应用程序 运行s 一段时间后,它会系统性地在此循环中失败,而在以前的迭代中它没有失败,列表较小。
调试,并使用pickle
模块,我在进入函数之前转储了列表。
当应用程序失败时,刚刚转储的列表在系统上是一个很大的列表(500k+ 元素)。
获取的文件大于或等于 70MB(二进制模式)。
我知道我有备用 RAM(使用 htop
,我看到我使用了大约 400MB,超过 2GB 可用)。
但是 CPU 经常处于 activity 的高百分比(超过 60%,有时达到 100%)。
当我从文件加载列表时,(应用程序已停止)我可以 运行 for
迭代而不会出现问题。该列表似乎没有损坏。
所以,我完全不知道哪里出了问题,除了可能 CPU activity 很高。如果 Python 确实没有足够的资源来工作,它有什么方法可以告诉我吗?我怎样才能检查这个?它的行为是什么?程序有没有可能在没有任何错误消息的情况下停止?
编辑 - 代码示例
请在下方找到应用程序冻结的代码。
代码本身正常执行。
执行上下文似乎是导致代码冻结的原因。
我可以确定该应用程序在名为 'Bermuda Triangle' 的 for
循环开始时冻结。
我可以使用 pickle
模块打印数据,但我无法在 for 循环中进行打印。
真正奇怪的是我得到了应该打印的文件,但这个文件 (dump_loop.txt
) 是空的。
我觉得这很奇怪,因为要么我应该有 0 个文件(注意循环开头的 os.remove
,这意味着我在每次迭代时系统地删除它)或者如果我有一个文件,里面应该有一些东西。
我确认当应用 运行 时(即 'normally',它没有被冻结),这两个文件被正确更新。
感谢您的帮助!
最佳,
import os
import json
import pickle
from collections import defaultdict
data = [('1599324732926-0',
{'data': '{"timestamp":1599324732.767, \
"receipt_timestamp":1599324732.9256856,\
"delta":true, \
"bid":{"338.9":0.06482,"338.67":3.95535}, \
"ask":{"339.12":2.47578,"339.13":6.43172} \
}'
}),
('1599324732926-1',
{'data': '{"timestamp":1599324732.767, \
"receipt_timestamp":1599324732.9256856,\
"delta":true, \
"bid":{"338.9":0.06482,"338.67":3.95535}, \
"ask":{"339.12":2.47578,"339.13":6.43172} \
}'
})]
def book_flatten(book: dict, timestamp: float, receipt_timestamp: float, delta: str) -> dict:
"""
Takes book and returns a list of dict, where each element in the list
is a dictionary with a single row of book data.
"""
ret = []
for side in ('bid', 'ask'):
for price, data in book[side].items():
ret.append({'side': side, 'price': price, 'size': data, 'timestamp': timestamp, 'receipt_timestamp': receipt_timestamp, 'delta': delta})
return ret
def read(data, dtype='l2_book', pair='AAPL-USD'):
key = f'{dtype}-{pair}'
if len(data) == 0:
return []
print("{!s}: Read {!s} messages from Redis".format(key, len(data)))
ret = []
ids=dict()
last_id=defaultdict(list)
# 1/Start - Lines added for debug
# Retrieve the last data before the app freezes
dump_list='./dump_list.data'
try:
os.remove(dump_list)
except OSError:
pass
with open(dump_list, 'wb') as filehandle:
# store the data as binary data stream
pickle.dump(data, filehandle)
dump_loop = './dump_loop.txt'
total_number = len(data)
counter=1
# 1/End
# The mysterious loop aka Bermuda Triangle
for update_id, update in data:
#2/Start - Lines added for debug
try:
os.remove(dump_loop)
except OSError:
pass
with open(dump_loop, 'w') as filehandle:
filehandle.write('Starting new loop for item {!s} over {!s}.\n'.format(counter, total_number))
#2/End
if dtype in {'l2_book'}:
update = json.loads(update['data'])
update = book_flatten(update, update['timestamp'], update['receipt_timestamp'], update['delta'])
for u in update:
for k in ('size', 'amount', 'price', 'timestamp', 'receipt_timestamp'):
if k in u:
u[k] = float(u[k])
ret.extend(update)
elif dtype in {'trades'}:
for k in ('size', 'amount', 'price', 'timestamp', 'receipt_timestamp', 'bid', 'ask'):
if k in update:
update[k] = float(update[k])
ret.append(update)
ids[key] = update_id
#3/Start - Lines added for debug
with open(dump_loop, 'a') as filehandle:
filehandle.write('Loop finished.\n')
counter+=1
#3/End
last_id[key] = ids[key][-1]
return ids, last_id, ret
好的,
所以有人建议我看一下系统日志(作为一个新手,我不知道这个)和 'voilà'!
新测试后,应用 my_app
在 17:45 崩溃。
这是系统日志在 17:45:
上的内容
Sep 6 17:45:12 cs1 kernel: [67093.681124] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-0.slice/session-32.scope,task=cryp>
Sep 6 17:45:12 cs1 kernel: [67093.681180] Out of memory: Killed process 15754 (my_app) total-vm:1752588kB, anon-rss:1332040kB, file-rss:32kB, shmem-rss:0kB, UID:0 pgtables:3144kB oom_sco>
Sep 6 17:45:12 cs1 kernel: [67093.764851] oom_reaper: reaped process 15754 (my_app), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
所以难怪 python 什么都不告诉我,它的进程被杀死了...
我正在开发一个程序,该程序有时会对列表进行 for
循环,其中一些很小,一些很大(500k + 个元素)。
当应用程序 运行s 一段时间后,它会系统性地在此循环中失败,而在以前的迭代中它没有失败,列表较小。
调试,并使用pickle
模块,我在进入函数之前转储了列表。
当应用程序失败时,刚刚转储的列表在系统上是一个很大的列表(500k+ 元素)。
获取的文件大于或等于 70MB(二进制模式)。
我知道我有备用 RAM(使用 htop
,我看到我使用了大约 400MB,超过 2GB 可用)。
但是 CPU 经常处于 activity 的高百分比(超过 60%,有时达到 100%)。
当我从文件加载列表时,(应用程序已停止)我可以 运行 for
迭代而不会出现问题。该列表似乎没有损坏。
所以,我完全不知道哪里出了问题,除了可能 CPU activity 很高。如果 Python 确实没有足够的资源来工作,它有什么方法可以告诉我吗?我怎样才能检查这个?它的行为是什么?程序有没有可能在没有任何错误消息的情况下停止?
编辑 - 代码示例
请在下方找到应用程序冻结的代码。 代码本身正常执行。 执行上下文似乎是导致代码冻结的原因。
我可以确定该应用程序在名为 'Bermuda Triangle' 的 for
循环开始时冻结。
我可以使用 pickle
模块打印数据,但我无法在 for 循环中进行打印。
真正奇怪的是我得到了应该打印的文件,但这个文件 (dump_loop.txt
) 是空的。
我觉得这很奇怪,因为要么我应该有 0 个文件(注意循环开头的 os.remove
,这意味着我在每次迭代时系统地删除它)或者如果我有一个文件,里面应该有一些东西。
我确认当应用 运行 时(即 'normally',它没有被冻结),这两个文件被正确更新。
感谢您的帮助! 最佳,
import os
import json
import pickle
from collections import defaultdict
data = [('1599324732926-0',
{'data': '{"timestamp":1599324732.767, \
"receipt_timestamp":1599324732.9256856,\
"delta":true, \
"bid":{"338.9":0.06482,"338.67":3.95535}, \
"ask":{"339.12":2.47578,"339.13":6.43172} \
}'
}),
('1599324732926-1',
{'data': '{"timestamp":1599324732.767, \
"receipt_timestamp":1599324732.9256856,\
"delta":true, \
"bid":{"338.9":0.06482,"338.67":3.95535}, \
"ask":{"339.12":2.47578,"339.13":6.43172} \
}'
})]
def book_flatten(book: dict, timestamp: float, receipt_timestamp: float, delta: str) -> dict:
"""
Takes book and returns a list of dict, where each element in the list
is a dictionary with a single row of book data.
"""
ret = []
for side in ('bid', 'ask'):
for price, data in book[side].items():
ret.append({'side': side, 'price': price, 'size': data, 'timestamp': timestamp, 'receipt_timestamp': receipt_timestamp, 'delta': delta})
return ret
def read(data, dtype='l2_book', pair='AAPL-USD'):
key = f'{dtype}-{pair}'
if len(data) == 0:
return []
print("{!s}: Read {!s} messages from Redis".format(key, len(data)))
ret = []
ids=dict()
last_id=defaultdict(list)
# 1/Start - Lines added for debug
# Retrieve the last data before the app freezes
dump_list='./dump_list.data'
try:
os.remove(dump_list)
except OSError:
pass
with open(dump_list, 'wb') as filehandle:
# store the data as binary data stream
pickle.dump(data, filehandle)
dump_loop = './dump_loop.txt'
total_number = len(data)
counter=1
# 1/End
# The mysterious loop aka Bermuda Triangle
for update_id, update in data:
#2/Start - Lines added for debug
try:
os.remove(dump_loop)
except OSError:
pass
with open(dump_loop, 'w') as filehandle:
filehandle.write('Starting new loop for item {!s} over {!s}.\n'.format(counter, total_number))
#2/End
if dtype in {'l2_book'}:
update = json.loads(update['data'])
update = book_flatten(update, update['timestamp'], update['receipt_timestamp'], update['delta'])
for u in update:
for k in ('size', 'amount', 'price', 'timestamp', 'receipt_timestamp'):
if k in u:
u[k] = float(u[k])
ret.extend(update)
elif dtype in {'trades'}:
for k in ('size', 'amount', 'price', 'timestamp', 'receipt_timestamp', 'bid', 'ask'):
if k in update:
update[k] = float(update[k])
ret.append(update)
ids[key] = update_id
#3/Start - Lines added for debug
with open(dump_loop, 'a') as filehandle:
filehandle.write('Loop finished.\n')
counter+=1
#3/End
last_id[key] = ids[key][-1]
return ids, last_id, ret
好的,
所以有人建议我看一下系统日志(作为一个新手,我不知道这个)和 'voilà'!
新测试后,应用 my_app
在 17:45 崩溃。
这是系统日志在 17:45:
Sep 6 17:45:12 cs1 kernel: [67093.681124] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-0.slice/session-32.scope,task=cryp>
Sep 6 17:45:12 cs1 kernel: [67093.681180] Out of memory: Killed process 15754 (my_app) total-vm:1752588kB, anon-rss:1332040kB, file-rss:32kB, shmem-rss:0kB, UID:0 pgtables:3144kB oom_sco>
Sep 6 17:45:12 cs1 kernel: [67093.764851] oom_reaper: reaped process 15754 (my_app), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
所以难怪 python 什么都不告诉我,它的进程被杀死了...