一、概述

运行一个程序时,默认会启动一个主线程,控制程序的运行,也成为控制线程或主线程。除了主线程之外,还可以新建子线程来处理程序,这就是多线程。多线程可以同时处理多个任务,提高效率,特别时IO操作比较多的时候。

二、多线程模块介绍

多线程模块_thread和threading。_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。threading是高级模块,对_thread进行了封装。绝大多数情况下,使用threading这个高级模块。

三、threading模块

threading模块提供的类:
Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

threading模块提供的常用方法:
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

threading 模块提供的常量:
threading.TIMEOUT_MAX 设置threading全局超时时间。

四、开启线程的两种方式

有函数和类两种方式创建多线程。

函数方式

启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。
Thread构造函数
Thread(group=None, target=None, name=None, args=(), kwargs={})
group: 线程组,目前还没有实现,库引用中提示必须是None;
target: 要执行的方法;
name: 线程名;
args/kwargs: 要传入方法的参数。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import threading
import time
def run(sec):
    print('%s 线程开始了!' %threading.current_thread().name)
    time.sleep(sec)
    print('%s 线程结束了!' %threading.current_thread().name)

if __name__ == '__main__':
    print('主线程开始执行:', threading.current_thread().name)
    s_time = time.time()
    thread_list = []
    for i in range(5):
        t = threading.Thread(target=run, args=(i,))
        thread_list.append(t)
    for t in thread_list:
        t.start()
    for t in thread_list:
        t.join()
    print('主线程执行结束', threading.current_thread().name)
    print('一共用时:', time.time()-s_time)

执行以上程序会输出如下结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
主线程开始执行: MainThread
Thread-1 线程开始了!
Thread-1 线程结束了!
Thread-2 线程开始了!
Thread-3 线程开始了!
Thread-4 线程开始了!
Thread-5 线程开始了!
Thread-2 线程结束了!
Thread-3 线程结束了!
Thread-4 线程结束了!
Thread-5 线程结束了!
主线程执行结束 MainThread
一共用时: 4.1290283203125

类方式

使用类方式需要写一个类,继承自threading.Thread类,然后重写run()方法。

例如:

 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
import threading
import time
class MyThread(threading.Thread):
    def __init__(self, sec):
        super().__init__()
        self.sec = sec

    def run(self):
        print('%s 线程开始了!' %threading.current_thread().name)
        time.sleep(self.sec)
        print('%s 线程结束了!' %threading.current_thread().name)

if __name__ == '__main__':
    print('主线程开始执行', threading.current_thread().name)
    s_time = time.time()
    my_thread_list = []
    for i in range(5):
        my_thread = MyThread(i)
        my_thread_list.append(my_thread)
    for i in my_thread_list:
        i.start()
    for i in my_thread_list:
        i.join()
    print('一共用时:', time.time()-s_time)
    print('主线程结束执行', threading.current_thread().name)

执行以上程序会输出如下结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
主线程开始执行 MainThread
Thread-1 线程开始了!
Thread-1 线程结束了!
Thread-2 线程开始了!
Thread-3 线程开始了!
Thread-4 线程开始了!
Thread-5 线程开始了!
Thread-2 线程结束了!
Thread-3 线程结束了!
Thread-4 线程结束了!
Thread-5 线程结束了!
一共用时: 4.059479713439941
主线程结束执行 MainThread

五、Thread实例对象的方法

start(): 启动线程。
isAlive(): 判断线程是否活动的。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        print('%s运行结束'%self.getName())

#建立子线程t
t=MyThread('子线程')
#启动线程
t.start()

#判断线程是否活动的。
if t.is_alive():
    print("子线程运行中")
else:
    print("子线程运行结束")

print("主线程运行结束")

执行以上程序会输出如下结果:

1
2
3
子线程运行中
主线程运行结束
子线程运行结束

getName(): 获取线程名。
setName(): 设置线程名。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        #getName()获取线程名
        print('%s运行结束'%self.getName())

#建立子线程t
t=MyThread('子线程')
#启动线程
t.start()
#设置线程名字
t.setName('子线程t')

print("主线程运行结束")

执行以上程序会输出如下结果:

1
2
主线程运行结束
子线程t运行结束

守护线程,表示该线程是不重要的,主线程退出时不需要等待这个线程执行完成。
isDaemon(bool): 判断是否是守护线程(默认False)。

setDaemon(bool): 设置是守护线程(默认False)。
默认False,主线程不回收此线程;设为True时,主线程结束时会将回收此线程,无论此线程是否完成。这样做的意义在于:避免子线程无限死循环,导致退不出程序。

注意,需要在线程start之前设置setDaemon(),否则会抛出RuntimeError异常。

不设置setDaemon(),默认是False。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        print('%s运行结束'%self.getName())

t=MyThread('子线程')
t.start()
if t.is_alive():
    print("主线程执行完毕")
else:
    print("主线程等待子线程")

执行以上程序会输出如下结果:

1
2
主线程执行完毕
子线程运行结束

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        print('%s运行结束'%self.getName())

t=MyThread('子线程')
t.setDaemon(True) #设置守护线程,主线程结束时,强制子线程结束
t.start()
if t.is_alive():
    print("主线程执行完毕")
else:
    print("主线程等待子线程")

执行以上程序会输出如下结果:

1
主线程执行完毕

join([timeout])
阻塞主线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)。主线程等待其返回然后再继续执行。

例如,没有join处理的时候

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        print('%s运行结束'%self.getName())

t=MyThread('子线程')
t.start()
print("主线程在等待子线程")
print("主线程运行结束")

执行以上程序会输出如下结果:

1
2
3
主线程在等待子线程
主线程运行结束
子线程运行结束

例如,有join处理的时候

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        print('%s运行结束'%self.getName())

t=MyThread('子线程')
t.start()
print("主线程在等待子线程")
#子线程t阻塞主线程。子线程运行完毕后,再继续运行主线程
t.join()
print("主线程运行结束")

执行以上程序会输出如下结果:

1
2
3
主线程在等待子线程
子线程运行结束
主线程运行结束

join有一个timeout参数:
当设置守护线程时(也就是setDaemon(true)),含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。
没有设置守护线程时(也就是setDaemon(false)),主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)

    def run(self):
        time.sleep(5)
        print('%s运行结束'%self.getName())

my_thread_list = []
for i in range(5):
    my_thread = MyThread(i)
    my_thread_list.append(my_thread)
for i in my_thread_list:
    i.start()
print("主线程在等待子线程")

#子线程阻塞主线程。子线程运行完毕后,再继续运行主线程
for i in my_thread_list:
    i.join(1)
print("主线程运行结束")

执行以上程序会输出如下结果:

1
2
3
4
5
6
7
主线程在等待子线程
主线程运行结束
Thread-1运行结束
1运行结束
2运行结束
3运行结束
4运行结束

转载请注明本网址。