And*_*s O 5 python memory debugging garbage-collection
我有一个 Python 脚本,它对 Word .docx 文件执行大量解析工作(并且它对所有以前的文件都有效)。它在运行中突然停止工作,没有抛出任何异常。整个代码被包装在一个 try- except 子句中,基本上是这样的:
try:
report.read_and_postprocess() #: My parsing process (with ALOT of code inside)
print("Finished...")
except NoObjectForElementError as error:
print("Known error")
raise error
except:
print("Other error")
raise
finally:
print("Write this!")
Run Code Online (Sandbox Code Playgroud)
为了定位错误,我尝试使用print()语句来隔离代码停止的位置。然而,当我靠近时,停止点移动到另一个地方。
在我看来,这似乎存在内存泄漏,或者可能是我的 Python 环境出现了其他一些限制——但我在调试这一点方面不太熟练。我查看了脚本的内存和 CPU 使用情况。在脚本结束时,它仅消耗约 87MB 内存,使计算机的总内存仅从 67% 移动到 68%。(我只查看 Windows 10 任务管理器,因此我不能保证在脚本停止之前内存不会瞬间激增)
我已经重新运行该脚本数百次,并且从未收到错误消息,除了两次出现此错误:
Python Fatal Error: GC Object already Tracked
Run Code Online (Sandbox Code Playgroud)
我不知道如何继续调试这个,有人有任何提示吗?这可能是由记忆引起的,或者我怎样才能找到?还有其他一些 Python 限制可能会导致这种情况吗?(例如,我读过有关 20 个嵌套 for 循环的限制 - 但对我来说不应该是这样)
更新:它在排队期间停止report.read_and_postprocess()。
有关环境的信息:Windows 10、Anaconda 3、Python 3.7。脚本在 anaconda 提示符下运行,并激活我的环境。
更新:我发现了这个提示:/sf/answers/241064561/ 看起来我的代码花费了大量时间来评估正则表达式。基本上,在观察跟踪时,类似这样的线条很常见:
sre_compile.py(596): return isinstance(obj, (str, bytes))
sre_compile.py(763): pattern = p
sre_compile.py(764): p = sre_parse.parse(p, flags)
--- modulename: sre_parse, funcname: parse
sre_parse.py(922): source = Tokenizer(str)
--- modulename: sre_parse, funcname: __init__
sre_parse.py(225): self.istext = isinstance(string, str)
sre_parse.py(226): self.string = string
sre_parse.py(227): if not self.istext:
sre_parse.py(229): self.decoded_string = string
sre_parse.py(230): self.index = 0
sre_parse.py(231): self.next = None
sre_parse.py(232): self.__next()
--- modulename: sre_parse, funcname: __next
sre_parse.py(234): index = self.index
sre_parse.py(235): try:
sre_parse.py(236): char = self.decoded_string[index]
sre_parse.py(240): if char == "\\":
sre_parse.py(247): self.index = index + 1
sre_parse.py(248): self.next = char
sre_parse.py(924): if pattern is None:
sre_parse.py(925): pattern = Pattern()
--- modulename: sre_parse, funcname: __init__
sre_parse.py(77): self.flags = 0
sre_parse.py(78): self.groupdict = {}
Run Code Online (Sandbox Code Playgroud)
我运行了跟踪,(至少这一次)它在 re.match 期间停止了,特别是这个 - 在循环的第三次迭代中:
def is_numeric(text):
""" Return whether a trimmed string is numeric
Numeric formats:
1
1.2 (US style)
1,2 (EU style)
1,200,340 (US style)
1 200 340 (other style)
1.200.340 (eu style?)
1,200,340.67
1 200 340,67
1 200 340.67
1.200.340,67
-23
-23.98
-2 454 981.21
+ 24
- 24
+ 24.9183
12321
543525,-
123123,
12389.
12 489.
12 432,
"""
if len(text) == 0:
return False
#: Try float
try:
float(text)
except ValueError:
pass
except:
raise
else:
return True
#: look for all characters that should not be in a number
if not re.match(r"^[-+0-9., ]*$", text):
return False
#: Verify numeric format
#: 1.200.200,78
#: 1,200,200.78
#: 1 200 200,78
#: 1 200 200.78
#: 1200200,78
#: 1200200.78
#: - 1200200.78
#: + 1.200.200,78
#: 1200200,-
#: -1 200 200,-
#: etc.
variants = ((r",", r"\."),
(r"\.", r","),
(r" ", r","),
(r" ", r"\."))
for (tho, dec) in variants:
dec_exp_opt = r"(%s[0-9]*)" % dec
if dec == ",":
dec_exp_opt = r"((%s)|(,-))" % dec_exp_opt
threesep = r"[1-9][0-9]{0,2}(%s[0-9]{3})*(%s)?" % (tho, dec_exp_opt)
nullsep = r"(([0-9]*(%s[0-9]+)?)|([0-9]+(%s)?))" % (dec, dec_exp_opt)
expr = r"^([-+][ \t]*)?((%s)|(%s))$" % (threesep, nullsep)
test = re.match(expr, text) #: IT HAS STOPPED HERE IN ITERATION 3!!
if test:
return True
return False
Run Code Online (Sandbox Code Playgroud)
此时尝试求解的表达式可能是(也可能不是)随机的:^([-+][ \t]*)?(([1-9][0-9]{0,2}( [0-9]{3})*((((,[0-9]*))|(,-)))?)|((([0-9]*(,[0-9]+)?)|([0-9]+((((,[0-9]*))|(,-)))?))))$for the value 2017-05-29(最好应该返回 false)。
(糟糕的?)正则表达式可以导致脚本停止而不引发异常,这是否有意义?模块中是否存在re可能导致此问题的缓存?
问题最终得到解决。我最终使用以下提示调试了程序:How can I see where my python script ishanging?
python -m trace --trace YOURSCRIPT.py
Run Code Online (Sandbox Code Playgroud)
使用跟踪模块可以让我找到脚本停止运行的位置。就我而言,我运行了一个循环,其中每次迭代都会执行一堆正则表达式检查。脚本在这些检查期间出现了错误,但每次都在不同的时间点。我不完全确定,但灾难性回溯可能是一个原因,正如 Mihai Andrei 的回答中所建议的那样。可以肯定的是,我运行了非常低效的正则表达式检查。我已经重写了脚本的整个正则表达式部分,现在它工作正常。
所以总而言之,我的问题的答案是:
trace以找出其停止位置。这让我想到(2)如果有人对为什么 Python 会出现错误而没有错误消息有更深入的解释,或者可以确认正则表达式中的内存泄漏可能导致这种情况,请添加到我的答案中!
| 归档时间: |
|
| 查看次数: |
15120 次 |
| 最近记录: |