Threading模块
在Python3中为了实现多线程, 可以通过_thread和threading两个标准库实现。在前面的教程中我们已经简单介绍了_thread模块的使用方法,_thread模块提供了低级别的、原始的线程以及一个简单的锁,它相比于threading模块的功能还是比较有限的。threading模块不仅包含_thread模块中的所有方法,还可以灵活地创建多线程程序,并且可以在多线程之间进行同步和通信。
threading模块实现多线程,主要是通过threading.Thread类实现。直接使用threading.Thread类的效果和_thread模块中的start_new_thread()方法效果一样。例如:
动手练一练:
import time
import threading
def fun(n, s):
print("第", n, "个线程开始执行时间:", time.ctime())
time.sleep(s)
print("第", n, "个线程结束执行时间:", time.ctime())
def main():
# 创建第一个Thread对象,通过target关键字参数指定线程函数fun,并通过args关键字参数传入参数
a = threading.Thread(target = fun, args = (1, 2))
# 启动第一个线程
a.start()
# 创建二个Thread对象
b = threading.Thread(target = fun, args = (2, 4))
b.start()
# 等待线程函数执行完毕
a.join()
b.join()
# 当前模块直接被执行
if __name__ == "__main__":
main()
执行以上代码,输出结果为:
第 1 个线程开始执行时间: Mon Apr 29 10:49:48 2024
第 2 个线程开始执行时间: Mon Apr 29 10:49:48 2024
第 1 个线程结束执行时间: Mon Apr 29 10:49:50 2024
第 2 个线程结束执行时间: Mon Apr 29 10:49:52 2024
从上面例子中的运行结果可以看出,通过threading.Thread类实现的效果和_thread模块实现的效果一模一样。在使用threading.Thread类之前,首先需要创建Thread类的实例对象,通过Thread类构造方法的target关键字参数执行线程函数,通过args关键字参数指定传给线程函数的参数。然后调用threading.Thread对象的start()方法启动线程,最后我们调用threading.Thread对象的join()方法等待两个线程函数都执行完毕后再退出程序。使用threading.Thread对象可以自动地帮助我们管理线程锁(创建锁、分配锁、获得锁、释放锁、检查锁等步骤)。可以看出,threading.Thread对象启动线程要比_thread模块中的锁方便很多。
在Python中,threading模块实现多线程,还可以通过继承threading.Thread类的方式,派生一个子类来创建线程。这种方法只要重写父类threading.Thread中的run()方法,然后再调用start()方法就能启动线程,并运行run()方法中的代码。例如:
动手练一练:
import time
import threading
# 从threading.Thread类派生一个子类MyThread
class MyThread(threading.Thread):
def __init__(self, number, sec):
# 调用父类的构造函数
super(MyThread,self).__init__()
self.number = number
self.sec = sec
# 重写父类的run方法
def run(self):
print("第", self.number, "个线程开始执行时间:", time.ctime())
time.sleep(self.sec)
print("第", self.number, "个线程结束执行时间:", time.ctime())
def main():
# 创建第一个线程
thread1 = MyThread(1, 2)
# 启动线程
thread1.start()
# 创建第二个线程
thread2 = MyThread(2, 4)
thread2.start()
# 等待两个线程执行完毕
thread1.join()
thread2.join()
# 当前模块直接被执行
if __name__ == "__main__":
main()
执行以上代码,输出结果为:
第 1 个线程开始执行时间: Mon Apr 29 11:56:32 2024
第 2 个线程开始执行时间: Mon Apr 29 11:56:32 2024
第 1 个线程结束执行时间: Mon Apr 29 11:56:34 2024
第 2 个线程结束执行时间: Mon Apr 29 11:56:36 2024
上面的例子中,通过threading.Thread类的派生类MyThread实现的效果和直接通过threading.Thread类实现的效果一模一样。派生类MyThread中重写了父类threading.Thread的run()方法。使用线程的时候,先创建一个子线程MyThread类的对象,然后对象调用start()方法启动线程,调用一些内部的启动方法后再调用我们重写的run()方法。