Python主线程何时退出
我正在阅读《Python标准库实例》,在第509页的时候有点困惑。
到目前为止,示例程序在所有线程完成工作之前,通常会隐式地等待退出。有些程序会启动一个守护线程,这种线程在主程序退出时不会阻塞。
但是当我运行一些代码时,得到的结果却正好相反。代码大致是这样的:
#!/usr/bin/env python
# encoding: utf-8
#
# Copyright (c) 2008 Doug Hellmann All rights reserved.
#
"""Creating and waiting for a thread.
"""
#end_pymotw_header
import threading
import time
def worker():
"""thread worker function"""
print 'Worker'
# time.sleep(10000)
return
threads = []
for i in range(5):
t = threading.Thread(target=worker)
threads.append(t)
t.start()
print "main Exit"
有时候结果是这样的:
Worker
Worker
WorkerWorker
main Exit
Worker
所以我想问一下,在Python中,主线程在启动几个线程后,什么时候会退出呢?
5 个回答
例如,下面是一个示例:
class ThreadA(Thread):
def __init__(self, mt):
Thread.__init__(self)
self.mt = mt
def run(self):
print 'T1: sleeping...'
time.sleep(4)
print 'current thread is ', self.isAlive()
print 'main thread is ', self.mt.isAlive()
print 'T1: raising...'
if __name__ == '__main__':
mt = threading.currentThread()
ta = ThreadA(mt)
ta.start()
logging.debug('main end')
> T1: 正在睡觉...
(主线程) 主程序结束
当前线程是 真
主线程是 假
T1: 正在唤醒...
你能看到主线程的活动状态是假的吧?
你的主线程会在 for 循环执行完后立刻结束。主线程会启动一些新的异步线程,也就是说它不会等这些新线程完成后再继续。所以在你的例子中,主线程会同时启动5个线程,然后自己就结束了。
注意,当你打印 main Exit
时,主程序并不会立刻结束,而是在之后才结束。看看这个程序:
import threading
import time
def worker():
"""thread worker function"""
print 'Worker'
time.sleep(1)
print 'Done'
return
class Exiter(object):
def __init__(self):
self.a = 5.0
print 'I am alive'
def __del__(self):
print 'I am dying'
exiter = Exiter()
threads = []
for i in range(5):
t = threading.Thread(target=worker)
threads.append(t)
t.start()
print "main Exit"
我创建了一个对象,它的唯一目的就是在被清理时打印“我快死了”。我并没有在任何地方显式地删除它,所以它只有在主线程结束时才会被清理,也就是当Python开始结束所有东西并把内存还给操作系统时。
如果你运行这个程序,你会发现当主线程完成时,工作线程仍然在工作,但这些对象依然存在。我快死了
这句话总是在所有工作线程完成它们的任务后才会被打印出来。
根据线程文档的说法:
当只剩下守护线程时,整个Python程序会退出。
这和你提到的那句话是一样的,但用词上有点不同,这也解释了你得到的结果。'主线程'会在你预期的时刻退出。注意,此时工作线程仍然在运行——你可以在你提供的测试输出中看到这一点。所以,主线程已经完成了,但整个进程仍然在运行,因为还有其他线程在继续工作。
区别在于,如果这些工作线程中有一些被设置为守护线程,那么当最后一个非守护线程完成时,它们会被强制终止。如果所有的工作线程都是守护线程,那么在你打印'主线程退出'后,整个进程会很快结束——你会回到系统的命令提示符。这种情况下,工作线程在那之后打印输出的情况非常少见(虽然由于竞争条件,这种情况并非不可能)。
主线程会在执行完你脚本中所有没有在单独线程中启动的代码后退出。
因为 t.start()
会启动一个新线程,然后返回到主线程,所以主线程会继续执行,直到脚本的最后一行,然后就退出了。
由于你启动的其他线程是非守护线程,它们会一直运行,直到完成。
如果你希望主线程在所有线程完成之前不退出,你需要明确地将它们 join
到主线程。调用 join
的线程会等待被连接的线程完成后再继续。
for i in range(5):
threads[i].join()
print "main Exit"
正如 @codesparkle 指出的,使用更符合 Python 风格的写法可以完全省略索引变量。
for thread in threads:
thread.join()
print "main Exit"