from threading import Thread
Thread属性
属性 | 描述 |
name | 线程名 |
ident | 线程标识符 |
daemon | 布尔标志,是否为守护线程 |
Thread方法
__init__( ['self', 'group=None', 'target=None', 'name=None', 'args=()', 'kwargs=None', '*', 'daemon=None'], ) |
实例化一个线程对象 |
start() | 开始执行线程 |
run() | 定义线程功能的方法(通常在子类中被应用开发者重写) |
join(timeout=None) | 直至启动的线程终止前一直挂起,除非给出timeout,否则一直阻塞 |
is_alive() | isAlive()已经放弃,返回一个布尔值,表示当前线程是否已经存活,True为存活 |
isDaemon() | 返回一个布尔值,如果为True,表示是守护线程 |
setDaemon(daemonic) | 设置self.daemon为daemonic布尔值 |
创建Thread实例举例
from time import sleep
from random import randint
def myfun(i):
sleep(randint(1,3))
print("线程编号:",i)
for i in range(1,5):
t = Thread(target=myfun, args=(i,))
t.start()
print("主线程运行结束")
运行结果:
# 主线程运行结束
# 线程编号: 1
# 线程编号: 4
# 线程编号: 2
# 线程编号: 3
注意看输出结果,线程编号由于加入了随时sleep,所以输出顺序是不一定的, 另外所有输出是在"主线程运行结束"后输出。
所有的线程对象创建后,并不会立即执行,而是需要t.start()
之后才会执行
使用join强制等待子线程运行结束
for i in range(1,5):
t = Thread(target=myfun, args=(i,))
t.start()
# 在 t.start() 之后
# 添加上一行
t.start()
t.join()
运行结果
# 线程编号: 1
# 线程编号: 2
# 线程编号: 3
# 线程编号: 4
# 主线程运行结束
加入join后,必须等待线程结束才能开始执行一个新的线程,主线程会阻塞到子线程执行完毕后
Thread子类实现
Thread子类需要重写run方法
class MyThread(Thread):
def __init__(self, func, args, name=''):
super().__init__()
self.name = name
self.func = func
self.args = args
def get_results(self):
return self.res
# 子类必须实现方法
def run(self):
self.res = self.func(*self.args)
def func1(arg1, arg2):
return arg1 * arg
def func2(arg1, arg2):
return arg1 ** arg2
t1 = MyThread(func1, (3,4), "")
t1.start()
t2 = MyThread(func2, (3,4), "")
t2.start()
# 输出线程执行结果
print(t1.get_results())
print(t2.get_results())
线程锁
锁有两种状态:锁定与未锁定,锁的方法也只有两个:获得锁,释放锁
锁的工作流程:
- 多个线程争夺一个锁
- 获得锁的线程进入执行
- 执行完毕,释放锁
- 重复以上步骤
导入Lock对象
from threading import Lock
实例Lock对象
lock = Lock()
lock实例方法
方法名 | 说明 |
acquire() | 请求锁 |
release() | 释放锁 |
不加锁示例
from time import sleep
data = []
def myfun(i):
global data
data.append(i)
sleep(randint(1,5))
data.append(i*10)
t_list = []
for i in range (1,10):
t = Thread(target=myfun, args=(i,))
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(data)
输出结果
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 60, 40, 70, 30, 80, 10, 50, 20, 90]
加锁示例
data = []
t_list = []
def myfun(i):
global data
lock.acquire()
data.append(i)
sleep(randint(1,5))
data.append(i*10)
lock.release()
for i in range (1,10):
t = Thread(target=myfun, args=(i,))
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(data)
加锁后的输出
# [1, 10, 2, 20, 3, 30, 4, 40, 5, 50, 6, 60, 7, 70, 8, 80, 9, 90]
预防死锁
如果在锁释放之前,线程退出,就会造成死锁,所以务必对这种情况进行处理
使用异常语句
# try:
# lock.acquire()
# ...
# finally:
# lock.release()
使用with语句
# with lock:
# ...
threading实用函数
函数名 | 说明 |
active_count() | 返回当前的活动线程数量 |
current_thread() | 返回对应于调用者的控制线程的Thread对象 |
enumerate() | 列出所有活动的Thread对象 |
local() | 返回local对象,用于保存线程的本地数据 |
setprofile(func) | 设置一个配置文件函数,用于创建所有的线程,func在每个线程开始运行之前被传递给sys.setprofile()函数 |
settrace(func) | 设置一个跟踪函数,用于已创建的所有线程,func在每个线程开始运行之前,被传递给sys.settrace() |
stack_size([size]) | 返回创建新线程使用的栈大小。可选的参数size指定创建线程时使用的大小,为4KB的倍数 |
讨论区