如何检测 Python 中外部模块的崩溃?

How do I detect a crash in an external module in Python?

我正在使用 Triangle 模块生成约束 Delaunay 三角剖分(可在 http://www.lfd.uci.edu/~gohlke/pythonlibs/ 获得)。在某些情况下,函数 triangle.triangulate 崩溃,并且 windows 说 'Python.exe has stopped responding'。我曾尝试使用 try/except 结构,如下例所示,但不一致地崩溃了。我假设三角剖分过程的一部分是随机的(见下文 'secondary question'),但我不完全确定。

这种不一致的情况令人担忧。我在 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'

我的问题:有没有办法像 'Try/Except' 结构一样捕获这个错误?或者,我是不是对三角形模块做错了什么?

编辑:

解决方案:引自 Gamrix 的 回复引出了解决方案。如果点之间的差异(欧几里德距离)太小,则三角剖分功能会崩溃。删除间隔小于 1e-12 的点解决了问题。

您所做的似乎已经定位了错误。如果它确实打印了 'about to tri',然后在打印 'completed tri' 之前崩溃了,那么看起来它在 triangle.triangulate 中崩溃了。该函数因引发异常而崩溃。在那种情况下,我唯一能想到的就是使用调试器逐步检查代码并尝试查看发生了什么。它可能与您的代码无关。看看这个 post:Random "pythonw.exe has stopped working" crashing 有什么方法可以 运行 在非 Windows 系统上测试这段代码是否实际上是 Windows问题?

根据您描述的行为,外部代码似乎陷入了死锁或无限循环。您无法在用户端捕捉到这一点,除非生成一个额外的线程,如果该过程花费的时间太长,该线程会杀死当前线程。

但是,即使这样也不能真正解决您面临的问题。我查看了三角形库(python 版本只是我链接到的版本的包装),我在网站上找到了以下内容。通读它,看看它是否解释了您的问题发生的原因:

Triangle doesn't terminate, or just crashes:

Bad things can happen when triangles get so small that the distance between their vertices isn't much larger than the precision of your machine's arithmetic. If you've compiled Triangle for single-precision arithmetic, you might do better by recompiling it for double-precision. Then again, you might just have to settle for more lenient constraints on the minimum angle and the maximum area than you had planned.

You can minimize precision problems by ensuring that the origin lies inside your vertex set, or even inside the densest part of your mesh. If you're triangulating an object whose x coordinates all fall between 6247133 and 6247134, you're not leaving much floating-point precision for Triangle to work with.

Precision problems can occur covertly if the input PSLG contains two segments that meet (or intersect) at an extremely angle, or if such an angle is introduced by the -c switch. If you don't realize that a tiny angle is being formed, you might never discover why Triangle is crashing. To check for this possibility, use the -S switch (with an appropriate limit on the number of Steiner points, found by trial-and-error) to stop Triangle early, and view the output .poly file with Show Me. Look carefully for regions where dense clusters of vertices are forming and for small angles between segments. Zoom in closely, as such segments might look like a single segment from a distance.

If some of the input values are too large, Triangle may suffer a floating exception due to overflow when attempting to perform an orientation or incircle test. (Read the section on exact arithmetic.) Again, I recommend compiling Triangle for double (rather than single) precision arithmetic.

Unexpected problems can arise if you use quality meshing (-q, -a, or -u) with an input that is not segment-bounded - that is, if your input is a vertex set, or you're using the -c switch. If the convex hull of your input vertices has collinear vertices on its boundary, an input vertex that you think lies on the convex hull might actually lie just inside the convex hull. If so, an extremely thin triangle is formed by the vertex and the convex hull edge beside it. When Triangle tries to refine the mesh to enforce angle and area constraints, extremely tiny triangles may be formed, or Triangle may fail because of insufficient floating-point precision

http://www.cs.cmu.edu/~quake/triangle.trouble.html

我在使用这个库时也遇到了一些问题,我试图获得具有完美对齐点的多边形的三角剖分。 我通过向输入顶点添加轻微的随机偏差来解决这个问题,比如 np.random.random([nvert, 2])*0.00001