如何检测 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 中外部模块的崩溃?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 cython 模块中使用外部包装类?

如何在 AWS CDK 创建的 Python Lambda 函数中安装外部模块?

python中json文件如何转换为外部链接

用于播放固定频率声音的Python库,无需外部模块

在没有外部模块的情况下在 Python 中播放声音?

如何使 VSCode 自动重新加载外部 *.py 模块?