线程的创建和启动
模块threading中定义了Thread类,该类专门用于管理线程。线程的创建方式分为使用Thread类创建和Thread子类创建两种,关于这两种方式的具体介绍如下。
1. 使用Thread类创建线程
可以直接通过Thread类的构造方法Thread()创建线程,该方法的声明如下:
Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
以上方法中,name参数表示线程的名称,默认由“Thread- N”形式组成,其中N为十进制数:其它参数与创建Process对象时用到的参数一致,这里就不再过多赘述了。
需要注意的是,Thread()方法创建线程默认是前台线程,该线程的特点是主线程会等待其执行结束后终止程序。
例如,创建一个Thread类对象thread_one,该对象用于执行task()函数,代码如下。
import threading
from threading import Thread
import time
def task():
time.sleep(3)
print('子线程运行,名称为:%s'% threading.currentThread().name)
thread_one = Thread(target=task) # 创建前台线程
使用构造方法创建线程时,还可以将daemon参数设为True,创建一个后台线程。示例如下:
thread_two = Thread(target=task, daemon=True) # 创建后台线程
后台线程总是与主线程同时终止。
2. 使用Thread子类创建线程
可以自定义一个继承自Thread的子类,在该子类中重写run()方法,再利用子类的构造方法创建线程。run()方法用于实现线程的功能与业务逻辑,可以在子类中重写该方法来自定义线程的行为。例如,定义一个继承自Thread的子类MyThread,该类中重写了__ init()__和run()方法,代码如下。
class MyThread(Thread):
def __ init__(self, num):
super().__ init__() # 调用父类的构造方法完成初始化
self.name = '线程' + str(num) # 设置线程的名称
def run(self): # 重写的run()方法
time.sleep(3)
message = self.name + '运行'
print(message)
创建一个MyThread类对象,示例如下:
for i in range(3):
thread_three = MyThread(i)
线程创建完之后,需要调用start()方法进行启动,以真正地将线程转换为就绪状态,等待操作系统地调度。例如,分别启动前面创建的前台线程thread_one、后台线程thread_two和自定义线程thread_three,程序启动和执行的结果分别如下所示:
(1)启动前台线程
thread_one.start()
执行程序,程序在三秒后打印如下信息:
子线程运行,名称为:Thread-1
由此可知,程序中只有一个前台线程和主线程时,它会等待前台线程执行结束后再终止。
(2)启动后台线程
thread_two.start()
执行程序,程序立即结束,没有打印任何信息。由此可知,程序中只有一个后台线程和主线程时,它不会等待后台线程执行结束就立即终止。
(3)启动自定义线程
for i in range(3):
thread_three = MyThread(i)
thread_three.start()
程序执行的结果如下所示:
线程1运行
线程0运行
线程2运行
程序中共创建了三个线程,由以上结果可知,每个线程按照自定义的行为输出了相应的语句。
注意:
当一个程序启动时,就有一个进程被操作系统创建,与此同时一个线程也立刻执行,该线程通常叫做程序的主线程(Main Thread)。如果需要再创建新的线程,那么新创建的线程就是主线程的子线程。
Python的threading模块中有个current_thread()函数,它永远返回当前线程的实例。主线程实例的名字叫Main Thread,子线程的名字在创建时可以指定,若没有指定名字,Python自动将线程命名为Thread-1、Thread-2……