1

我遇到的问题是,在我的 IronPython 应用程序中,线程正在创建但从未清理过,即使它们运行的​​方法已经退出。在我的应用程序中,我以两种方式启动线程:a) 使用 Python 风格的线程(threading.Thread 的子类,在其 run() 方法中执行某些操作),以及 b) 使用 .NET 'ThreadStart' 方法。Python 风格的线程按预期运行,并且在它们的 'run()' 退出后,它们会被清理掉。.NET 风格的线程永远不会被清理,即使它们已经退出。你可以调用 del、Abort,任何你想要的,它对它们没有任何影响。

以下 IronPython 脚本演示了该问题:

import System
import threading
import time
import logging

def do_beeps():
    logging.debug("starting do_beeps")
    t_start = time.clock()
    while time.clock() - t_start < 10:
        System.Console.Beep()
        System.Threading.Thread.CurrentThread.Join(1000)
    logging.debug("exiting do_beeps")

class PythonStyleThread(threading.Thread):

    def __init__(self, thread_name="PythonStyleThread"):
        super(PythonStyleThread, self).__init__(name=thread_name)

    def run(self):
        do_beeps()

class ThreadStarter():

    def start(self):
        t = System.Threading.Thread(System.Threading.ThreadStart(do_beeps))
        t.IsBackground = True
        t.Name = "ThreadStartStyleThread"
        t.Start()

if __name__ == '__main__':

    logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=logging.DEBUG, datefmt='%H:%M:%S')

    # Start some ThreadStarter threads:
    for _ in range(5):
        ts = ThreadStarter()
        ts.start()
        System.Threading.Thread.CurrentThread.Join(200)

    # Start some Python-style threads:
    for _ in range(5):
        pt = PythonStyleThread()
        pt.start()
        System.Threading.Thread.CurrentThread.Join(200)

    # Do something on the main thread:
    for _ in range(30):
        print(".")
        System.Threading.Thread.CurrentThread.Join(1000)

在 PyDev 中对此进行调试时,我看到的是所有线程在创建时都按预期显示在“调试”视图中:

pydev 调试器中的所有线程

但是,虽然 Python 风格的那些在完成后会消失,但 .NET / ThreadStart 会一直保留到主线程退出。

pydev调试器中的挥之不去的线程

如图所示,在调试器中,有问题的线程以名称“Dummy-4”、“Dummy-5”等出现,而 Pythonic 线程以我给它们的名称(“PythonStyleThread”)出现。查看我的 IronPython 安装中的 threading.py 文件,我看到有一个名为“_DummyThread”的类,它是 Thread 的一个子类,它将其“名称”设置为“名称=_newname(“Dummy-%d”)”,所以它看起来通过使用 ThreadStart 我最终得到了 _DummyThreads。该课程的评论还说:

# Dummy thread class to represent threads not started here.
# These aren't garbage collected when they die, nor can they be waited for.

这可以解释为什么我无法摆脱它们。

但我不想要'DummyThread'。我只想要正常的,它们表现得很好并且在他们完成他们的事情后被垃圾收集。

现在,所有这一切有点奇怪的是,除非我设置记录器,否则我根本看不到调试器中的 DummyThread 条目(尽管它们仍在运行)。这可能是 PyDev 调试器的一个有趣之处,或者它可能相关。为什么日志记录应该对此有任何影响?我可以通过不登录我的线程来解决我的问题吗?

在这里,它说:

“有可能创建了“虚拟线程对象”。这些是与“外来线程”相对应的线程对象,它们是在线程模块之外启动的控制线程,例如直接从 C 代码。虚拟线程对象的功能有限;它们总是被认为是活的和恶魔的,不能被join编辑。它们永远不会被删除,因为不可能检测到外来线程的终止。

这让我想知道为什么我会不幸和他们在一起?

虽然我有一个解决方法,我可以在我目前使用 .NET 'ThreadStart' 线程的任何地方使用 Python 风格的线程。线程子类,但我并不热衷于这样做,因为我在某些地方使用 .NET 风格的线程是因为他们给了我一个Abort方法(而 Python 没有)。我知道中止线程是一件坏事,但应用程序是一个单元测试框架,我 a) 需要在线程中运行单元测试,并且 b) 无法控制它们的内容(它们是由第三方编写的),因此我无法定期检查这些线程上的“请好好关闭我”标志,并且在极端情况下可能需要粗鲁地杀死它们。

所以a)为什么我得到 DummyThreads,b)这与日志记录有什么关系,c)我能做些什么呢?

谢谢。

4

0 回答 0