操作系统能够调度和切换的最小单元实际上是线程。
对于IO操作来说,多线程和多进程性能差别不大。
有两种方法可以进行多线程编程。
1.使用多线程编程的两种方法
(1)直接实例化一个Thread对象
from threading import Thread import time def task1(): print("task1开始执行") time.sleep(5) print("task1执行结束") def task2(): print("task2开始执行") time.sleep(3) print("task2结束执行") if __name__ == "__main__": t1 = Thread(target=task1) t2 = Thread(target=task2) start_time = time.time() t1.start() t2.start() run_time = time.time() - start_time print("执行时间:%s"%run_time)
执行结果:
task1开始执行
task2开始执行
执行时间:0.0009980201721191406
task2结束执行
task1执行结束
t1和t2属于并发执行,t1和t2开始之后,并不会等到执行完毕之后再执行下面的代码。
因为在t1和t2之外还有一个主线程,我们通过debug可以看的一清二楚。
在主线程结束之后,会等待其中的子线程全部执行完毕之后才会退出,不然就不会打印子线程的结果信息。
我们可以做一些设置:
t1.setDaemon(True)
执行结果:
task1开始执行
task2开始执行
执行时间:0.0009980201721191406
task2开始执行
setDaemon的意思是,将t1设置为守护线程,当主线程结束之后,守护线程也会随之结束。
如果你希望一定要等待线程执行完成,可以适用join。
from threading import Thread import time def task1(): print("task1开始执行") time.sleep(5) print("task1执行结束") def task2(): print("task2开始执行") time.sleep(3) print("task2结束执行") if __name__ == "__main__": t1 = Thread(target=task1) t1.setDaemon(True) #主线程不用等待t1执行完毕之后才退出,但是依然要等待t2执行完毕。 t2 = Thread(target=task2) start_time = time.time() t1.start() t2.start() t1.join() t2.join() run_time = time.time() - start_time print("执行时间:%s"%run_time) 执行结果: task1开始执行 task2开始执行 task2结束执行 task1执行结束 执行时间:5.0016233921051025
加入join之后,不管你是否设置了守护线程,都会等到线程执行结束,才会接着往下执行。
(2)直接继承Thread类,重写run方法
from threading import Thread import time class T1(Thread): def run(self): print("task1开始执行") time.sleep(5) print("task1执行结束") class T2(Thread): def run(self): print("task2开始执行") time.sleep(3) print("task2结束执行") if __name__ == "__main__": t1 = T1() t2 = T2() t1.start() t2.start() t1.join() t2.join() print("主线程结束")
两种方式其实是一样的,一个是作为子类一个是作为对象,方法和属性基本相同。
同时我们也可以通过super调用父类的__init__方法。
在代码逻辑比较简单的时候,适用第一种方法没有什么毛病,如果逻辑比较复杂使用第二种方法当然更合适。
不管你要适用那种方法,你都是操作的一个对象,如果你想获取结果,当然应该把结果绑定到对象上去。
2.Thread中的方法一览
daemon:等于isDaemon
getName:获取线程名
ident:线程标识符
isAlive:查看线程的运行状态
isDaemon:是否是守护线程
is_alive
join:等待线程执行完毕
name:property属性,可以给线程设置name
run:线程的逻辑部分,一般会重写这个方法
setDaemon:设置守护线程
setName:设置线程名
start:开始执行线程