多线程编程——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
    29
    import 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
7
starting 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
    39
    import 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
7
starting 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
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
39
40
import threading
from time import sleep, ctime

loops = [4, 2]

class MyThread(threading.Thread): # 继承

def __init__(self, func, args, name=''):
threading.Thread.__init__(self) # 必须调用基类的构造函数
self.name = name
self.func = func
self.args = args

def run(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 = MyThread(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
7
starting 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
18
import 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

待续中。。。。。。