【问题标题】:Python deadlock related to packaging and mayavi?打包和mayavi相关的python死锁?
【发布时间】:2013-12-15 22:13:58
【问题描述】:

我有一个奇怪的问题,希望有人能解释一下。

我有一段复杂的代码,从一个充满脚本的目录开始,我决定将其重新编写成一个包。此代码更改似乎是一些奇怪死锁出现的触发因素。

下面是对该问题进行规范再现的尝试;失败了,因为此代码按预期运行。实际重现问题可能需要大量代码;但我无法想象在上下文中违规代码 sn-p 有什么不同。

import numpy as np
from scipy.sparse import csr_matrix
from threading import Thread

def dummy():
    print 'this is printed'
    I = np.eye(3)
    print 'all is still fine'
    csr_matrix(I)
    print 'this is never printed; csr_matrix appears to be a trigger for deadlock'
    print np.ones(4)
    print 'same problem; somehow, printing ndarrays is no longer cool either'

thr = Thread(target=dummy)
thr.start()

也许文档中的这个简洁评论是相关的?我不确定我是否完全理解这里所说的内容

http://docs.python.org/2/library/threading#importing-in-threaded-code

首先,除了在主模块中,导入不应该产生产生新线程然后以任何方式等待该线程的副作用。如果生成的线程直接或间接尝试导入模块,则不遵守此限制可能会导致死锁。

一些上下文:我正在使用 python 2.7,numpy 1.8,我尝试从 mayavi/traitsui 线程中生成这个新线程(我不明白为什么它应该是相关的,并且在包结构之前工作正常,但是没问题)。此外,在我生成的线程中有大量 numpy/scipy 代码执行得非常好;它只是打印 ndarrays 并创建稀疏矩阵,到目前为止已被证明是死锁的触发器。

我怀疑与 mayavi 有一些奇怪的交互,因为关闭 mayavi 窗口会导致所有死锁的线程重新开始运行。也许这些特定的语句触发了 python 线程让步给了 mayavi 线程,但它们又不知何故无法再次获得焦点?

非常感谢任何有助于进一步缩小这个谜团的提示!

【问题讨论】:

  • 很难说,因为问题可能与您没有在此处复制的代码细节有关。你join()ing 这些线程中的任何一个吗?您是否像您给我们的示例一样在模块的顶层启动它们?如果您正在做这两件事,那么这就是文档中的评论告诉您不要做的事情。在执行模块代码时,会持有一个全局导入锁。以这种方式调用csr_matrix() 确实会导致导入,因此它也会尝试获取导入锁。出现僵局。不要那样做。
  • 感谢您的帮助。这就是我对文档的理解;但我没有做这两件事。我不会在任何地方加入任何事情。也许 mayavi 在幕后做某事;但这不是文档警告的内容,不是吗?线程从 UI 对象中的方法启动,作为对用户输入的响应。此外,此时 csr_matrix 早已被导入其他地方;它应该被缓存,所以导入锁仍然起作用吗?
  • 还有;关于是什么让 csr_matrix 和 ndarray.__repr__ 特别的任何线索?为什么我的线程在到处乱跑的代码中愉快地前进; numpy scipy 和一大堆导入,但无论我在哪里调用这两个函数中的任何一个,都会一直卡住?
  • 在密集的ndarray causes an import 上调用csr_matrix()。如果你能想出一个完整的例子来说明这个问题,我也许可以提供帮助。
  • 当您说您使用 Mayavi 时,您的意思是您在脚本中使用 mlab.show(),而不是将您的代码集成到 Mayavi 应用程序中?

标签: python multithreading packaging mayavi


【解决方案1】:

从您的 cmets 看来,您似乎在某个子模块的顶层启动了 UI 事件循环。这不是一个好主意,因为它会导致文档中提到的完全相同的问题。 import foo 永远不应该启动 UI 事件循环。问题是主线程抓住了导入锁来处理模块的导入。此模块在完成导入之前启动 UI 事件循环。这与等待其他线程完成的情况基本相同;您正在等待 UI 循环完成。如果您的 UI 启动了其他线程,则在其他线程中运行的代码将无法导入任何内容(csr_matrix()ndarray.__repr__() 导入其他模块),因为主线程仍然持有导入锁。

【讨论】:

  • 我明白了; configure_traits 都创建一个线程,然后等待它,这违反了文档中指定的规则(如果 mayavi 文档强调这一点也不会受到伤害)。但是,我不明白的是,只有在使用非常狭窄的函数子集时才会发生死锁(同样,大量充斥着导入的代码在 mayavi 线程和其子线程中都可以毫无问题地执行)。
  • 我仍然不能说我完全掌握了这里发生的事情,我必须说我对这一切的 Pythonicity 感到有些失望。但尽管如此,仔细阅读文档并坚持下去确实可以解决问题。感谢您的来回;即使我最终想通了,我也不能接受这个作为答案。
  • configure_traits() 不创建线程。它只是运行 UI 循环并且在 UI 循环完成之前不会返回。所有 UI 循环的行为都是这样的。 The documentation of configure_traits() 告诉你这个。我希望您使用的线程实际上都不会像调用csr_matrix()ndarray.__repr__() 那样在线程内部导入东西,只是使用在线程启动之前导入模块命名空间的模块。跨度>
  • 我的印象是所有特征应用程序都在内部使用多个线程?但不管;对 configure_traits() 的调用是阻塞的,所以我的工作线程仍然是导入的间接副作用,所以导入锁仍然在原地。
  • 但是如果 configure_traits() 没有创建线程,那不是使文档不完整吗?问题应该是在模块级别创建一个线程然后加入它。但又一次;我不等待任何线程。如果 mayavi/traits 也没有,那是什么?我说文档中的警告不够笼统;不仅要避免加入线程,而且任何类型的阻塞代码,如 UI 循环都会造成麻烦。一旦您了解发生了什么,就暗示了这一点;但我几乎认为这个警告与我无关,因为无论如何我都没有加入任何线程!
猜你喜欢
  • 2013-06-08
  • 2015-04-03
  • 1970-01-01
  • 1970-01-01
  • 2011-03-08
  • 2017-05-29
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多