多线程编程——threading模块
threading模块的Thread类
threading模块的Thread类是主要的执行对象。它有thread模块中没有的许多函数。使用Thread类可以有很多方法来创建线程。这里介绍其中比较相似的三种方法。
- 方法一:创建Thread的实例,传给它一个函数。如下啊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29import threading
from time import sleep, ctime
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: # start threads
threads[i].start()
for i in nloops: # wait for all threads to finish
threads[i].join()
print('all done at:', ctime())
if __name__ == '__main__':
main()
当运行完后,打印结果如下:1
2
3
4
5
6
7starting at: Wed Apr 10 16:28:53 2019
start loop 0 at: Wed Apr 10 16:28:53 2019
start loop 1 at: Wed Apr 10 16:28:53 2019
loop 1 done at: Wed Apr 10 16:28:55 2019
loop 0 done at: Wed Apr 10 16:28:57 2019
all done at: Wed Apr 10 16:28:57 2019
[Finished in 4.2s]
- 方法二:创建Thread的实例,传给它一个可调用的类实例
在创建线程时,与传入函数相似的一个方法是传入一个可调用的类的实例,用于线程执行——这种方法更加接近面向对象的多线程编程。这种可调用的类包含一个执行环境,比起一个函数或者从一组函数中选择而言,有更好的灵活性。现在你有了一个类对象,而不仅仅是单个函数或者一个函数列表/元组。
在方法一的代码中添加一个新类ThreadFunc,并进行一些其他的轻微改动,得到下面的代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39import threading
from time import sleep, ctime
loops = [4, 2]
class ThreadFunc(object):
def __init__(self, func, args, name=''):
self.name = name
self.func = func
self.args = args
def __call__(self):
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: # create all threads
t = threading.Thread(target=ThreadFunc(loop, (i, loops[i]), loop.__name__))
threads.append(t)
for i in nloops: # start threads
threads[i].start()
for i in nloops: # wait for all threads to finish
threads[i].join()
print('all done at:', ctime())
if __name__ == '__main__':
main()
当运行完后,得到了如下的输出:1
2
3
4
5
6
7starting at: Wed Apr 10 16:51:55 2019
start loop 0 at: Wed Apr 10 16:51:55 2019
start loop 1 at: Wed Apr 10 16:51:55 2019
loop 1 done at: Wed Apr 10 16:51:57 2019
loop 0 done at: Wed Apr 10 16:51:59 2019
all done at: Wed Apr 10 16:51:59 2019
[Finished in 4.2s]
- 方法三:派生Thread的子类,并创建子类的实例
这种方法要介绍的这个例子要调用Thread()的子类(实际上就是继承Thread类鞭编写我们自己需要的线程类),和上一个创建可调用类的例子有些类似。当创建线程时使用子类要相对更容易阅读。
1 | import threading |
当运行完后,得到了如下的输出:1
2
3
4
5
6
7starting at: Wed Apr 10 17:07:01 2019
start loop 0 at: Wed Apr 10 17:07:01 2019
start loop 1 at: Wed Apr 10 17:07:01 2019
loop 1 done at: Wed Apr 10 17:07:03 2019
loop 0 done at: Wed Apr 10 17:07:05 2019
all Done at: Wed Apr 10 17:07:05 2019
[Finished in 4.2s]
本例中将对Thread子类化,而不是直接对齐实例化。这将使我们在定制线程对象时拥有更多的灵活性,也能够简化线程创建的调用过程。
现在对MyThread类进行修改,增加一些调试信息的输出,并将其存储为一个名为myThread的独立模块,以便于后面自己用到这个类。myThread.py:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import threading
from time import sleep, ctime
class MyThread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self) # 必须调用基类的构造函数
self.name = name
self.func = func
self.args = args
def getResult(self):
return self.res
def run(self):
print('starting', self.name, 'at:', ctime())
self.res = self.func(*self.args)
print(self.name, 'finished at:', ctime())
threading模块的其他函数
除了各种同步和线程对象外,threading模块还提供了一些函数:
active_count():当前活动的Thread对象个数
current_thread:返回当前的Thread对象
enumerate():返回当前活动的Thread对象列表
settrace(func):为所有线程设置一个trace函数
setprofile(func):为所有线程设置一个profile函数
stack_size(size=0):返回新创建线程的栈大小;或为后续创建的线程设定栈的大小为size
待续中。。。。。。