我遇到的问题是,在我的 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 中对此进行调试时,我看到的是所有线程在创建时都按预期显示在“调试”视图中:
但是,虽然 Python 风格的那些在完成后会消失,但 .NET / ThreadStart 会一直保留到主线程退出。
如图所示,在调试器中,有问题的线程以名称“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)我能做些什么呢?
谢谢。