18.5 threading模块
Threading模块支持守护线程,它们是这样工作的:守护线程一般是一个等待客户请求服务器,如果客户提出请求,它就在那等着。如果你设定一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。
如果你的主线程要退出的时候,不用等待那些子线程完成,那就设定这些线程的daemon属性。即,在线程开始(调用thread.start())之前,调用setDaemon()函数设定线程的daemon标志(thread.setDaemon(True))就表示这个线程"不重要".
如果你想要等待子线程完成再退出,那就什么都不用做,或者显式地调用thread.setDaemon(False)以保证其daeMon标志为False。你可以调用thread.isDaemon()函数来判断其daemon标志的值。新的子线程会继承其父线程的daemon标志。整个Python会在所有的非守护线程退出后才会结束,即进程中没有非守护线程存在的时候才结束。
18.5.1 thread类
import threading
from time import ctime, sleep
loops = [4, 2]
def loop(nloop, nsec):
print 'start loop ', nloop, ' at: ', ctime()
sleep(nsec)
print 'loop ', nloop, ' done at: ', ctime()
def main():
print 'starting at: ', ctime()
threads = []
nloops = range(len(loops))
for i in nloops:
t = threading.Thread(target = loop, args = (i, loops[i]))
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join()
print 'all DONE at: ', ctime()
main()
实例化每个Thread对象的时候,我们把函数(target)和参数(args)传进去,得到返回的Thread实例。实例化一个Thread(调用Thread())与调用thread.start_new_thread()之间最大的区别就是,先的线程不会立即开始。当你创建线程对象,但不想马上开始运行线程的时候,这是一个非常有用的同步特性。
join()会等到线程结束,或者在给了timeout参数的时候,等到超时为止。
join()的另一个比较重要的方面是它可以完全不用调用。一旦线程启动之后,就会一直运行,知道线程的函数结束,退出为止。如果你的主线程除了等待线程结束外,还有其他的事情要做,那就不用调用join(),只有你要等待线程结束的时候才要调用join()。
import threading
from time import ctime, sleep
loops = [4, 2]
class ThreadFunc(object):
def __init__(self, func, args, name=''):
self.func = func
self.args = args
self.name = name
def __call__(self):
apply(self.func, self.args)
def loop(nloop, nsec):
print 'start loop ', nloop, ' at: ', ctime()
sleep(nsec)
print 'loop ', nloop, ' done at: ', ctime()
def main():
print 'starting at: ', ctime()
threads = []
nloops = range(len(loops))
for i in nloops:
t = threading.Thread(target = ThreadFunc(loop, (i, loops[i]), loop.__name__))
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join()
print 'all DONE at: ', ctime()
main()
创建新线程的时候,Thread对象会调用我们的ThreadFunc对象,这时会用到一个特殊函数__call__()。