Python多线程编程详解:创建、守护线程与常用方法
本文详细介绍Python中多线程的创建方式,包括函数式与类继承式两种方法。深入解析threading模块中Thread类的核心方法,如join()实现线程阻塞等待,setDaemon(True)设置守护线程以控制主进程退出行为,以及isAlive、activeCount等状态查询方法,帮助开发者掌握Python并发编程基础。
在Python中,创建线程主要存在两种途径:一是通过函数直接调用,二是通过定义类来实例化线程对象。
函数式创建是指直接调用_thread模块中的start_new_thread()函数来生成一个新的线程。
基于类的创建方式则是通过继承threading.Thread子类,从而包装并管理一个线程对象。
1.线程的创建
1.1 通过thread类直接创建
import threading
import time
def foo(n):
time.sleep(n)
print("foo func:",n)
def bar(n):
time.sleep(n)
print("bar func:",n)
s1=time.time()
#创建一个线程实例t1,foo为这个线程要运行的函数
t1=threading.Thread(target=foo,args=(3,))
t1.start() #启动线程t1
#创建一个线程实例t2,bar为这个线程要运行的函数
t2=threading.Thread(target=bar,args=(5,))
t2.start() #启动线程t2
print("ending")
s2=time.time()
print("cost time:",s2-s1)
在示例程序中,定义了两个函数,它们会先执行几秒钟的休眠操作,随后打印一条提示信息。
接着,程序实例化两个线程对象,分别调用上述函数执行任务,最后统计并打印整个程序的总执行时间。
程序运行结果如下:
ending cost time: 0.002000093460083008 foo func: 3 bar func: 5
执行时,父线程首先运行并打印“ending”,随后记录父线程的执行时间,最后才轮到子线程执行。
1.2 通过thread类来继承式创建
import threading
import time
# 定义MyThread类,其继承自threading.Thread这个父类
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print("ok")
time.sleep(2)
print("end t1")
# 对类进行实例化
t1=MyThread()
# 启动线程
t1.start()
print("ending")
2. Thread类的一些常用方法
2.1 join():在子线程完成之前,主线程将一直被阻塞
需要注意的是,线程的join方法必须在子线程的start方法被调用之后才能定义。 在第一个示例代码中加入两行关键代码,具体调整如下:
import threading
import time
def foo(n):
time.sleep(n)
print("foo func:",n)
def bar(n):
time.sleep(n)
print("bar func:",n)
s1=time.time()
t1=threading.Thread(target=foo,args=(3,))
t1.start()
t2=threading.Thread(target=bar,args=(5,))
t2.start()
t1.join() # 阻塞t1线程
t2.join() # 阻塞t2线程
print("ending")
s2=time.time()
print("cost time:",s2-s1)
再次执行程序,观察到的运行结果如下:
foo func: 3 bar func: 5 ending cost time: 5.002285957336426
当程序运行至子线程t1的foo方法时,会执行3秒的睡眠;与此同时,子线程t2也在进行睡眠操作。
待子线程t1的睡眠结束后,开始打印foo函数中的print语句,随后子线程t1执行完毕。
2秒钟之后,子线程t2的睡眠结束,开始打印bar函数中的print语句,随后子线程t2也执行完成。
在此期间,主线程一直处于阻塞状态,直到所有子线程执行完成后,主线程才会继续执行。
2.2 setDeamon(True)
setDaemon方法的作用是将线程声明为守护线程,该设置必须在调用start()方法之前完成。 若未设置为守护线程,程序可能会因等待子线程而无限挂起。
在程序执行过程中,当创建一个主线程并由此衍生出一个子线程时,主线程和子线程会各自独立运行。
当主线程运行结束时,它会检查子线程是否已执行完毕;如果子线程已完成,则主线程会等待子线程彻底退出后再结束自身。
然而,有时希望主线程执行完毕后,无论子线程是否完成,都立即随主线程一起退出,此时就需要调用setDaemon方法。
以第一个例子为例,现在希望让子线程t1和t2随主线程关闭,相关代码如下:
import threading
import time
def foo(n):
print("foo start")
time.sleep(n)
print("foo end...")
def bar(n):
print("bar start")
time.sleep(n)
print("bar end...")
s1 = time.time()
t1 = threading.Thread(target=foo, args=(3,))
t1.setDaemon(True)
t1.start()
t2 = threading.Thread(target=bar, args=(5,))
t2.setDaemon(True)
t2.start()
print("ending")
s2 = time.time()
print("cost time:", s2 - s1)
程序运行结果如下 :
foo start bar start ending cost time: 0.003000020980834961
可以看到,将t1和t2都声明为守护线程后,程序自上而下执行:先执行子线程t1中的foo方法,打印第一条语句,随后子线程t1进入睡眠状态。
接着子线程t2执行,打印bar函数的第一条print语句,随后子线程t2进入睡眠状态,程序控制权切换回主线程。
主线程打印完“ending”语句后,检测到子线程t1和t2已被设置为守护线程,因此无需等待子线程执行完成,而是立即结束并打印整个程序的执行时间。
整个程序随即跟随主线程一起关闭。
2.3 子线程的一些其他方法
isAlive() #判断一个线程是否是活动线程
getName() #返回线程的名字
setName() #设置线程的名字
import threading
import time
def foo(n):
time.sleep(n)
print("foo func:", n)
def bar(n):
time.sleep(n)
print("bar func:", n)
s1 = time.time()
t1 = threading.Thread(target=foo, args=(3,))
t1.setDaemon(True)
print("线程还未启动时,判断t1是否是活动的线程:", t1.isAlive()) # 线程还未启动,所以是False
t1.start() # 启动线程
print("线程已启动时,判断t1是否是活动的线程:", t1.isAlive()) # 线程已启动,所以是True
print("修改前的线程名为:",t1.getName()) # 获取线程名
t1.setName("t1") #设置线程名
print("修改后的线程名为:",t1.getName()) # 获取线程名
t1.join()
print("线程执行完成时,判断t1是不否是活动的线程:", t1.isAlive()) # 线程已执行完成,所以是False
# print(threading.activeCount())
print("ending")
s2 = time.time()
print("cost time:", s2 - s1)
程序执行结果:
线程还未启动时,判断t1是否是活动的线程: False 线程已启动时,判断t1是否是活动的线程: True 修改前的线程名为: Thread-1 修改后的线程名为: t1 foo func: 3 线程执行完成时,判断t1是不否是活动的线程: False ending cost time: 3.001171588897705
3.threading模块提供的一些方法
threading.currentThread() #返回当前的线程变量
threading.enumerate() #返回一个包含正在运行的线程的列表,不包括启动前和终止后的线程
threading.activeCount() #返回正在运行的线程数量,等同于len(threading.enumerate())
import threading
import time
def foo(n):
time.sleep(n)
print("foo func:", n)
def bar(n):
time.sleep(n)
print("bar func:", n)
s1 = time.time()
t1 = threading.Thread(target=foo, args=(3,))
t1.setDaemon(True)
t1.start()
t2 = threading.Thread(target=bar, args=(5,))
t2.setDaemon(True)
t2.start()
print("程序中正在运行的线程数量:",threading.activeCount())
print("程序中当前的线程变量:",threading.currentThread())
print("当前正在运行的线程的列表:",threading.enumerate())
print("ending")
s2 = time.time()
print("cost time:", s2 - s1)
程序执行结果:
程序中正在运行的线程数量: 3 程序中当前的线程变量: <_MainThread(MainThread, started 7064)> 当前正在运行的线程的列表: [<_MainThread(MainThread, started 7064)>, <Thread(Thread-1, started daemon 6384)>, <Thread(Thread-2, started daemon 2640)>] ending cost time: 0.002000093460083008
总结
以上所述是小编给大家介绍的详解python中的线程,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对本站网站的支持!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













