如何检测 Python 中外部模块的崩溃?
Posted
技术标签:
【中文标题】如何检测 Python 中外部模块的崩溃?【英文标题】:How do I detect a crash in an external module in Python? 【发布时间】:2015-11-10 15:09:03 【问题描述】:我正在使用 Triangle 模块生成受约束的 Delaunay 三角剖分(可在 http://www.lfd.uci.edu/~gohlke/pythonlibs/ 获得)。在某些情况下,函数 triangle.triangulate 崩溃,并且 Windows 显示“Python.exe 已停止响应”。我尝试过使用 try/except 结构,如下例所示,它会不一致地崩溃。我假设三角测量过程的一部分是随机的(参见下面的“次要问题”),但我并不完全确定。
这种不一致相当令人担忧。我在 Windows 上。
from shapely.geometry import Polygon, MultiPolygon, LineString
import numpy as np
import triangle
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import random
def meshXOR(polyRef, shape, otherVerts, otherSegs, otherHole):
verts = []
verts3 = []
segs = []
outerLength = len(polyRef[shape[0]])
for i in range(outerLength-1):#-1 because xorpoly duplicates first point into last spot
verts.append((polyRef[shape[0]][i][0],polyRef[shape[0]][i][1])) #append the point to the verts array which will be fed into the delaunay triangulator
if i == outerLength - 2:
segs.append([i,0])
else:
segs.append([i,i+1])
h = []
for cInd in shape[1]:
shift = len(verts)
innerLength = len(polyRef[cInd])
for i in range(innerLength-1):
verts.append((polyRef[cInd][i][0],polyRef[cInd][i][1]))
if i == innerLength - 2:
segs.append([i+shift,shift])
else:
segs.append([i+shift,i+1+shift])
h += list(Polygon(polyRef[cInd]).representative_point().coords)
print 'verts are: ', verts
#output: verts are: [(0.0, 5.0), (0.0, 10.0), (10.0, 10.0), (10.0, 0.0), (0.0, 0.0), (0.0, 5.0), (7.0, 3.0), (7.0, 7.0)]
print 'segs are: ', segs
#output: segs are: [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0], [5, 6], [6, 7], [7, 5]]
print 'holes are: ', h
#output: holes are: [(5.25, 6.0)]
print 'verts: ', verts == otherVerts
print 'segs: ', segs == otherSegs
print 'hole: ', h == otherHole
return verts, segs, h
pA = Polygon([[0.0,0.0],[10.0,0.0],[10.0,10.0],[0.0,10.0]])
pB = Polygon([[0.0,5.0],[7.0,3.0],[7.0,7.0]])
xorPoly = pA.symmetric_difference(pB)
if xorPoly.geom_type == 'Polygon': xorPoly = MultiPolygon([xorPoly])
otherVerts = [(0.0, 5.0), (0.0, 10.0), (10.0, 10.0), (10.0, 0.0), (0.0, 0.0), (0.0, 5.0), (7.0, 3.0), (7.0, 7.0)]
otherSegs = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0], [5, 6], [6, 7], [7, 5]]
otherHole = [(5.25,6.0)]
xorPolys = []
shapes = []
for poly in xorPoly:
shapes.append([len(xorPolys), [], len(shapes)])
xorPolys.append(list(poly.exterior.coords))
for ip in poly.interiors:
shapes[-1][1].append(len(xorPolys))
xorPolys.append(list(ip.coords))
try:
verts, segs, holes = meshXOR(xorPolys, shapes[0], otherVerts, otherSegs, otherHole) # i even tried placing it here
except:
print 'failed'
if len(holes)>0:
A = dict(vertices = np.asarray(verts), segments = np.asarray(segs), holes = holes)
else:
A = dict(vertices = np.asarray(verts), segments = np.asarray(segs))
print 'about to tri'
B = triangle.triangulate(A, opts = 'pi') #this is the step that try/except doesn't work on
print 'completed tri'
try:
B_t = B["triangles"].tolist()
except:
print 'no trianlges'
if B_t != []:
cols = []
import random
for tri in B_t:
cols.append(random.random())
plt.figure()
plt.gca().set_aspect('equal')
xy = np.asarray(verts)
plt.tripcolor(xy[:,0], xy[:,1], B_t, facecolors=np.array(cols))
#for tri in B_t:
#print 'tri is: ', [verts[t] for t in tri]
plt.show()
else:
print 'no triangles'
我的问题:有没有办法做类似“尝试/排除”结构的事情来捕捉这个错误?或者,我对三角形模块做错了吗?
编辑:
解决方案:Gamrix 的 回复中的引用引出了解决方案。如果点之间的差异太小(欧几里得距离),则三角函数会崩溃。删除间隔小于 1e-12 的点解决了这个问题。
【问题讨论】:
【参考方案1】:根据您描述的行为,外部代码似乎陷入死锁或无限循环。您无法在用户端捕捉到这一点,除非产生一个额外的线程来杀死当前线程,如果进程花费太长时间。
但是,即使这样也不能真正解决您面临的问题。我查看了三角形库(python 版本只是我链接到的版本的包装),我在网站上找到了以下内容。通读它,看看它是否解释了您的问题发生的原因:
三角形没有终止,或者只是崩溃:
当三角形变得太小以至于距离 他们的顶点之间并不比你的精度大多少 机器的算术。如果您已将 Triangle 编译为单精度 算术,你可以通过重新编译它来做得更好 双精度。再说一次,你可能只需要满足于更多 对最小角度和最大面积的限制比你宽松 已经计划好了。
您可以通过确保原点位于 在您的顶点集内,甚至在您的网格最密集的部分内。 如果您要对一个 x 坐标都在 6247133 和 6247134,你不会留下太多的浮点精度 供 Triangle 使用。
如果输入 PSLG 包含两个 以极端角度相交(或相交)的线段,或者如果这样的 角度由 -c 开关引入。如果你没有意识到一个微小的 角度正在形成,你可能永远不会发现为什么三角形是 崩溃。要检查这种可能性,请使用 -S 开关(带有 施泰纳点数的适当限制,由 试错)提前停止三角形,并查看输出 .poly 文件显示给我。仔细寻找密集集群的区域 顶点正在形成并且线段之间的角度很小。放大 密切相关,因为这样的段可能看起来像一个单独的段 距离。
如果某些输入值太大,Triangle 可能会遭受 尝试执行时因溢出而导致的浮动异常 方向或圆周测试。 (阅读精确算术部分。) 同样,我建议为双精度(而不是单精度)编译 Triangle 精确算术。
如果您使用质量网格划分(-q、-a 或 -u) 输入不是段有界的 - 也就是说,如果您的输入是顶点集,或者您正在使用 -c 开关。如果凸包 您的输入顶点在其边界上有共线顶点,输入 您认为位于凸包上的顶点实际上可能只是 凸包内。如果是这样,一个非常薄的三角形由 顶点和它旁边的凸包边。当三角试图 细化网格以强制执行角度和面积约束,非常小 可能会形成三角形,或者三角形可能因不足而失败 浮点精度
http://www.cs.cmu.edu/~quake/triangle.trouble.html
【讨论】:
我也读过这个。不幸的是,经过大量时间的测试,我已经排除了这些原因。我明天再看看确认。 这段话确实指向了正确的答案。重新检查后,我发现有些点之间的距离很小。据我所知,删除欧几里得距离小于 1e-12 的点解决了这个问题。【参考方案2】:您所做的似乎已经本地化了错误。如果它确实打印了“about to tri”,然后在打印“completed tri”之前崩溃了,那么它似乎在 triangle.triangulate 中崩溃了。该函数因引发异常而崩溃。在那种情况下,我唯一能想到的就是用调试器单步调试代码并尝试查看发生了什么。不过,它可能与您的代码无关。看看这个帖子:Random "pythonw.exe has stopped working" crashing 有什么方法可以在非 Windows 系统上运行这段代码来测试它是否真的是 Windows 问题?
【讨论】:
我目前只能访问 Windows。我将尝试访问一些不同的操作系统。【参考方案3】:我在使用这个库时也遇到了一些问题,我试图对具有完美对齐点的多边形进行三角剖分。 我通过向输入顶点添加轻微的随机偏差来解决这个问题,例如 np.random.random([nvert, 2])*0.00001
【讨论】:
解释为什么/如何解决 OP 的问题可能会提高这篇文章的质量。以上是关于如何检测 Python 中外部模块的崩溃?的主要内容,如果未能解决你的问题,请参考以下文章