一. 什么是线程
线程也是一种多任务编程的方式,可以使用计算机多核资源。线程又被称为轻量级的进程,线程具有以下特征:
- 线程是计算机核心分配的最小单位。
- 一个进程可以包含多个线程。
- 线程也是一个运行过程,也要消耗计算机资源;多个线程共享其进程的资源和空间。
- 线程也拥有自己特有的资源属性,比如指令集,TID等。
- 线程无论创建、删除还是运行,资源消耗都小于进程。
- 多个线程之间并行执行,互不干扰。
二. 创建线程
Python 中使用 threading 模块创建线程,关于threading模块的常用类/方法的使用总结如下:
import threading
t = threading.Thread(name, target, *agrs, **kwargs)
功能:创建线程对象。
参数:name线程名称;target线程函数;args元组给线程函数传参;kwargs字典给线程函数传参。
t.start()
启动线程。
t.join([timeout])
回收线程。
t.is_alive()
查看线程状态。
t.name
线程名称,默认为 Thread-1。
t.setName()
设置线程名称。
threading.currentThread()
获取当前线程对象。
t.daemon
t.setDaemon(True)
设置守护线程。 默认t.daemon=False,主线程退 出不会影响分支线程;如果设置为True,则主线程退出分支线程也会退出。
- 主线程退出指的是所有非守护线程运行结束时,主线程才退出。(并不是主线程代码执行完,主线程就会立即退出)。
- daemon属性的设置在start前。
- 一般设置daemon后,不会再使用 join。
t.isDaemon()
判断 daemon 属性。
示例代码一 创建Thread的实例,传递一个函数
from threading import Thread,currentThread
from time import sleep
def fun_thread(sec,tname):
'''线程函数,用于修改线程的名称'''
print("启动线程-->",currentThread().getName(),":",currentThread().is_alive())
print("setName修改线程名称")
currentThread().setName(tname)
sleep(sec)
print("{}线程结束".format(currentThread().getName()))
threads = [] # 维护线程
for i in range(3):
t = Thread(target=fun_thread, name="thread-%d"%i,
args=(3,"My"+str(i)+"Thread"))
threads.append(t)
t.start()
for t in threads:
t.join()
运行结果:
三. 封装自己的线程类
通过继承Thread类,并运行Thread类中的init方法以获取父类属性,并重写run方法,在线程启动后,将自动执行run方法。
示例代码二 创建Thread的实例,传递一个可调用的类实例
import threading
from time import sleep,ctime
from threading import currentThread
loops = [4,2]
class ThreadFunc(object):
def __init__(self, func, args):
self.func = func
self.args = args
def __call__(self):
self.func(*self.args)
def loop(nloop, nsec):
print(ctime(), currentThread().getName(), 'start loop', nloop)
sleep(nsec)
print(ctime(), currentThread().getName(), 'end loop', nloop)
def main():
threads = []
nloops = range(len(loops))
for i in nloops:
# 由于自定义的类中重写了__call__方法,使得类的实例可以像函数一样被调用
# 调用时会自动执行__call__这个特殊方法
t = threading.Thread(target=ThreadFunc(loop, (i, loops[i])))
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join()
if __name__ == "__main__":
main()
运行结果:由于自定义的ThreadFunc类中重写了call方法,使得类的实例可以像函数一样被调用,调用时会自动执行call这个特殊方法。因此可以将类实例赋值给Thread的target参数。
示例代码三 派生Thread的子类,并创建子类的实例
import threading
from time import sleep, ctime
loops = (4, 2)
class MyThread(threading.Thread):
def __init__(self, target, args):
super().__init__()
self.target = target
self.args = args
def run(self):
self.target(*self.args)
def loop(nloop, nsec):
print(ctime(), 'start loop', nloop)
sleep(nsec)
print(ctime(), 'end loop', nloop)
def main():
threads = []
nloops = range(len(loops))
for i in nloops:
t = MyThread(loop,(i, loops[i]))
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join()
if __name__ == "__main__":
main()