概述
本节主要介绍python线程的使用,与对进程的使用类似
线程的生命周期
五种状态:
- 新建(new): 新创建的线程经过初始化后,进入就绪(Runnable)状态
- 就绪(Runnable):等待线程调度。调度后进入运行状态
- 运行(Running):当就绪的线程被调度并获得CPU时,便进入运行状态
- 阻塞(Blocked):暂停运行,解除阻塞后进入Runnable状态重新等待调度
- 死亡(Dead):线程方法执行完毕返回或者异常终止
从“运行”进入“阻塞”(Blocked):
- 同步:线程中获取同步锁,但是资源已经被其他线程锁定时,进入Locked状态,直到该资源可获取(获取的顺序由Lock队列控制)
- 睡眠:线程运行sleep()或join()方法后,线程进入Sleeping状态。区别在于sleep等待固定的时间,而join是等待子线程执行完。当然join也可以指定一个“超时时间”。从语义上来说,如果两个线程a,b, 在a中调用b.join(),相当于合并(join)成一个线程。最常见的情况是在主线程中join所有的子线程。
- 等待:线程中执行wait()方法后,线程进入Waiting状态,等待其他线程的通知(notify)。
例子
模拟一个线程 下载2个大文件,一个文件下载后,才能下载另一个文件,速度慢,效率低下
import time
import os
def task():
# 模拟耗时任务,如:迅雷下载
for i in range(101):
print("下载文件1,进度:",i)
time.sleep(0.5)
def task2():
# 模拟耗时任务,如:迅雷下载
for i in range(101):
print("下载文件2,进度:",i)
time.sleep(0.5)
print("pid:{},父pid:{}".format(os.getpid(),os.getppid()))
task()
task2()
Thread类使用说明
导入模块
import threading
或者
from threading import Thread
创建对象
语法:
Thread(self, group=None, target=None, name=None,args=(), kwargs=None, *, daemon=None)
参数说明:
- group:一般不使用
- target:表示调用对象
- name:为别名
- args:表示调用对象的位置参数元组
- kwargs:表示调用对象的关键字参数字典
常用属性
- name:当前线程别名,在实例化时通过参数name指定,默认为Thread=N,N为从1开始递增的整数
常用方法
start():启动线程实例
is_alive():判断线程实例是否还在执行,返回布尔值
join([timeout]):参见
run():参见 python-Thread子类创建进程
threading模块使用说明
- threading.current_thread():返回当前线程对象
- threading.main_thread():返回主线程对象
- threading.enumerate():返回当前存在的所有线程对象的列表
- threading.active_count(): 返回当前存活的线程对象的数量。通过计算len(threading.enumerate())长度而来
例子:多线程同时下载文件
import time
import os
import threading
def task():
# 模拟耗时任务,如:迅雷下载
for i in range(101):
print("线程:",threading.current_thread().name,",下载文件1,进度:",i)
time.sleep(0.5)
def task2():
# 模拟耗时任务,如:迅雷下载
for i in range(101):
print("线程:",threading.current_thread().name,"下载文件2,进度:",i)
time.sleep(0.5)
print("pid:{},父pid:{}".format(os.getpid(),os.getppid()))
# 创建线程,执行task()函数,注意:后面不要加小括号(),表示调用
t1 = threading.Thread(target=task)
# 启动线程
t1.start()
# 创建线程,执行task()函数,注意:后面不要加小括号(),表示调用
t2 = threading.Thread(target=task2)
# 启动线程
t2.start()
例子:共享变量
为了提高速度,启动2个线程,下载同一个文件,第一个线程从0开始下载,第二个线程从51开始下载
而且修改总进度
import time
import os
import threading
# 全局变量,多线程共享变量
count = 0
def task():
global count
# 模拟耗时任务,如:迅雷下载
for i in range(51):
print(threading.current_thread().name+"--下载文件1,进度:" ,i)
count += 1
# 在函数中访问全局变量
print("总进度:",count)
time.sleep(0.2)
def task2():
global count
# 模拟耗时任务,如:迅雷下载
for i in range(51,101):
print(threading.current_thread().name+"--下载文件1,进度:" ,i)
count += 1
# 在函数中访问全局变量
print("总进度:", count)
time.sleep(0.2)
print("pid:{},父pid:{}".format(os.getpid() ,os.getppid()))
# 让子线程执行task()函数
t1 = threading.Thread(target=task)
# 调用函数
t1.start()
# 让子线程执行task2()函数
t1 = threading.Thread(target=task2)
# 调用函数
t1.start()
