threading模块

#更高级别的threading不仅提供了Thread类,还提供了各种非常好用的同步机制。
#_thread模块不支持守护线程,当主线程退出时,所有子线程无论是否在工作,都会被强制退出。threading模块支持守护线程,守护线程一般时一个等待客户请求的服务器,如果没有客户提出请求,就一直等着。如果设定一个线程为守护线程,就表示这个线程不重要,在进程退出时,不用等待这个线程退出。如果主线程退出时不用等待子线程完成,就要设定这些线程的daemon属性,即在线程Thread.start()开始前,调用setDaemon()函数设定线程的daemon标志(Thread.setDaemon(True)),表示这个线程“不重要”,如果一定要等待子线程执行完成再退出主线程,就什么都不用做或显式调用Thread.setDaemon(False)以保证daemon标志为False,可以调用Thread.isDaemon()函数判断daemon标志的值。新的子线程会继承父线程的daemon标志,整个Python在所有非守护线程退出后才会结束,即进程中没有非守护线程存在时才会结束。
 
threading的thread类
#Thread有很多_thread模块里没有的函数,Thread对象的函数很丰富。下面创建一个Thread的实例,传给他一个函数。示例如下:
 1 #!/usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #threading的thread类
 4 
 5 import threading
 6 from time import sleep
 7 from datetime import datetime
 8 
 9 loops=[4,2]
10 date_time_format='%y-%M-%d %H:%M:%S'
11 
12 def date_time_str(date_time):
13     return datetime.strftime(date_time,date_time_format)
14 
15 def loop(n_loop,n_sec):
16     print('线程(',n_loop,')开始执行:',date_time_str(datetime.now()),',先休眠(',n_sec,')秒')
17     sleep(n_sec)
18     print('线程(',n_loop,')休眠结束,结束于:',date_time_str(datetime.now()))
19 
20 def main():
21     print('---所有线程开始执行:',date_time_str(datetime.now()))
22     threads=[]
23     n_loops=range(len(loops))
24 
25     for i in n_loops:
26         t=threading.Thread(target=loop,args=(i,loops[i]))
27         threads.append(t)
28 
29     for i in n_loops:        #start threads
30         threads[i].start()
31 
32     for i in n_loops:        #wait for all
33         threads[i].join()    #thread to finish
34 
35     print('---所有线程执行结束于:',date_time_str(datetime.now()))
36 
37 if __name__=='__main__':
38     main()
#执行结果如下:
1 D:\Pythonworkspace>python threading_thread.py
2 ---所有线程开始执行: 18-31-30 09:31:54
3 线程( 0 )开始执行: 18-31-30 09:31:54 ,先休眠( 4 )秒
4 线程( 1 )开始执行: 18-31-30 09:31:54 ,先休眠( 2 )秒
5 线程( 1 )休眠结束,结束于: 18-31-30 09:31:56
6 线程( 0 )休眠结束,结束于: 18-31-30 09:31:58
7 ---所有线程执行结束于: 18-31-30 09:31:58
#由执行结果我们看到,实例化一个Thread(调用Thread())与调用_thread.start_new_thread()最大的区别是新的线程不会立即开始。创建线程对象却不想马上开始运行线程时,Thread是一个很有用的同步特性。所有线程都创建之后,再一起调用start()函数启动,而不是每创建一个线程就启动。而且不用管理一堆锁的状态(分配锁、获得锁、释放锁、检查锁的等状态),只要简单对每个线程调用join()主线程,等待子线程结束即可。join()还可以设置timeout参数,即主线程的超时时间。
#join()的另一个比较重要的方面是可以完全不用调用。一旦线程启动,就会一直运行,直到线程的函数结束并退出为止。如果主线程除了等线程结束外,还有其他事情要做,就不用调用join(),只有在等待线程结束时才调用。
#我们再看示例,创建一个Thread的实例,并传给它一个可调用的类对象。代码如下:
 1 #!/usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #threading_join()
 4 
 5 import threading
 6 from time import sleep
 7 from datetime import datetime
 8 
 9 loops=[4,2]
10 date_time_format='%y-%M-%d %H:%M:%S'
11 
12 class ThreadFunc(object):
13     def __init__(self,func,args,name=''):
14         self.name=name
15         self.func=func
16         self.args=args
17 
18     def __call__(self):
19         self.func(*self.args)
20 
21 def date_time_str(date_time):
22     return datetime.strftime(date_time,date_time_format)
23 
24 def loop(n_loop,n_sec):
25     print('线程(',n_loop,')开始执行:',date_time_str(datetime.now()),',先休眠(',n_sec,')秒')
26     sleep(n_sec)
27     print('线程(',n_loop,')休眠结束,结束于:',date_time_str(datetime.now()))
28 
29 def main():
30     print('---所有线程开始执行:',date_time_str(datetime.now()))
31     threads=[]
32     nloops=range(len(loops))
33 
34     for i in nloops:
35         t=threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
36         threads.append(t)
37 
38     for i in nloops:     #start all threads
39         threads[i].start()
40 
41     for i in nloops:    #wait for completion
42         threads[i].join()
43 
44     print('---所有线程执行结束于:',date_time_str(datetime.now()))
45 
46 if __name__=='__main__':
47     main()
#执行结果如下:
1 D:\Pythonworkspace>python threading_join().py
2 ---所有线程开始执行: 18-30-30 11:30:26
3 线程( 0 )开始执行: 18-30-30 11:30:26 ,先休眠( 4 )秒
4 线程( 1 )开始执行: 18-30-30 11:30:26 ,先休眠( 2 )秒
5 线程( 1 )休眠结束,结束于: 18-30-30 11:30:28
6 线程( 0 )休眠结束,结束于: 18-30-30 11:30:30
7 ---所有线程执行结束于: 18-30-30 11:30:30
#由执行结果看到,与传一个函数很相似的一个方法是,在创建线程时,传一个可调用的类的实例供线程启动时执行,这是多线程编程的一个面向对象的方法。相对于一个或多个函数来说,类对象可以使用类的强大功能。创建线程时,Thread对象会调用ThreadFunc对象,这时会用到一个特殊函数__call__()。由于已经有了要用的参数,因此不用再传到Thread()的构造函数中。对于一个参数的元组,要使用self.func(*self.args)方法。
#从Thread派生一个子类,创建这个子类的实例,从上面的代码派生的代码如下:
 1 #!/usr/bin/python3
 2 #-*-coding:UTF-8-*-
 3 #threading___call__
 4 
 5 import threading
 6 from time import sleep
 7 from datetime import datetime
 8 
 9 loops=[4,2]
10 date_time_format='%y-%M-%d %H:%M:%S'
11 
12 class MyThread(threading.Thread):
13     def __init__(self,func,args,name=''):
14         threading.Thread.__init__(self)
15         self.name=name
16         self.func=func
17         self.args=args
18 
19     def getResult(self):
20         return self.res
21 
22     def run(self):
23         print('starting',self.name,'at:',date_time_str(datetime.now()))
24         self.res=self.func(*self.args)
25         print(self.name,'finished at:',date_time_str(datetime.now()))
26 
27 def date_time_str(date_time):
28     return datetime.strftime(date_time,date_time_format)
29 
30 def loop(n_loop,n_sec):
31     print('线程(',n_loop,')开始执行:',date_time_str(datetime.now()),',先休眠(',n_sec,')秒')
32     sleep(n_sec)
33     print('线程(',n_loop,')休眠结束,结束于:',date_time_str(datetime.now()))
34 
35 def main():
36     print('---所有线程开始执行:',date_time_str(datetime.now()))
37     threads=[]
38     n_loops=range(len(loops))
39 
40     for i in n_loops:
41         t=MyThread(loop,(i,loops[i]),loop.__name__)
42         threads.append(t)
43 
44     for i in n_loops:
45         threads[i].start()
46 
47     for i in n_loops:
48         threads[i].join()
49 
50     print('---所有线程执行结束于:',date_time_str(datetime.now()))
51 
52 if __name__=='__main__':
53     main()
#执行结果如下:
 1 D:\Pythonworkspace>python threading_call.py
 2 ---所有线程开始执行: 18-12-30 15:12:55
 3 starting loop at: 18-12-30 15:12:55
 4 线程( 0 )开始执行: 18-12-30 15:12:55 ,先休眠( 4 )秒
 5 starting loop at: 18-12-30 15:12:55
 6 线程( 1 )开始执行: 18-12-30 15:12:55 ,先休眠( 2 )秒
 7 线程( 1 )休眠结束,结束于: 18-12-30 15:12:57
 8 loop finished at: 18-12-30 15:12:57
 9 线程( 0 )休眠结束,结束于: 18-12-30 15:12:59
10 loop finished at: 18-12-30 15:12:59
11 ---所有线程执行结束于: 18-12-30 15:12:59
#由代码片段和执行结果我们看到,子类化Thread,MyThread子类的构造函数一定要先调用基类的构造函数,特殊函数__call__()在子类中,名字要改为run()。在Thread类中,加入一些用于调试的输出信息,把代码保存到MyThread模块中,并导入这个类。使用self.func()函数运行这些函数,并把结果保存到实现的self.res属性中,创建一个新函数getResult()得到结果。
posted @ 2018-02-03 23:48  爱你无目的  阅读(340)  评论(0编辑  收藏  举报