多线程的优点:①使用线程可以吧占据长时间的程序中的任务放到后台去处理
②用于界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
③程序的运行速度可能加快
④在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就发挥作用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程进行控制。
每个线程都有他自己的一组寄存器称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
注意:①线程可以被抢占(中断)
②在其他线程正在运行时,线程可以暂时搁置(也称为睡眠)---这就是线程的退让
线程可以分为:①内核线程:由操作系统内核 创建和撤销
②用户线程:不需要内核支持而在用户程序中实现的线程
Python3多线程中常用的两个模块未:①_thread ② threading(推荐使用)
其中,thread模块已经被废弃,用户可以使用threading替代,所以在Python3中不能再使用 thread模块。为了兼容性,Python3将 thread重命名为 _thread。
threading创建线程:threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
threading模块除了包含_thread模块中的所有方法外,还提供了额外的方法:
①threading.currentThread(): 返回当前的线程变量
②threading.enumerate():返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
③threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate()有相同的效果。
除了使用方法外,线程模块提供了thread类来处理线程,thread类提供了如下方法:
①run():用以表示线程活动的方法
②start(): 启动线程活动
③join([time]): 让主线程阻塞,等待其创建的线程执行完成
④isAlive(): 返回线程是否活动
⑤getName(): 返回线程名
⑥setName(): 设置线程名
一个无线程程序:
import timestart = time.time()
people = 500 # 假设有500个人
def action(num):
global people
while people>0:
people -= 50 # 每次运输50人
print("车辆编号:%d, 当前车站人数:%d" %(num, people))
time.sleep(1)
num = 1 # 车辆编号
action(num)
end = time.time()
print("Duration time: %0.3f" %(end-start))
结果:
车辆编号:1, 当前车站人数:450
车辆编号:1, 当前车站人数:400
车辆编号:1, 当前车站人数:350
车辆编号:1, 当前车站人数:300
车辆编号:1, 当前车站人数:250
车辆编号:1, 当前车站人数:200
车辆编号:1, 当前车站人数:150
车辆编号:1, 当前车站人数:100
车辆编号:1, 当前车站人数:50
车辆编号:1, 当前车站人数:0
Duration time: 10.001
一个单线程程序:
import threading
import timestart = time.time()
people = 500 # 假设有500个人
def action(num):
global people
while people>0:
people -= 50 # 每次运输50人
print("车辆编号:%d, 当前车站人数:%d" %(num, people))
time.sleep(1)
num = 1 # 车辆编号
vehicle = threading.Thread(target=action, args=(num,)) # 新建车辆
vehicle.start() # 启动车辆
vehicle.join() # 检查到站车辆
end = time.time()
print("Duration time: %0.3f" %(end-start))
结果:
车辆编号:1, 当前车站人数:450
车辆编号:1, 当前车站人数:400
车辆编号:1, 当前车站人数:350
车辆编号:1, 当前车站人数:300
车辆编号:1, 当前车站人数:250
车辆编号:1, 当前车站人数:200
车辆编号:1, 当前车站人数:150
车辆编号:1, 当前车站人数:100
车辆编号:1, 当前车站人数:50
车辆编号:1, 当前车站人数:0
Duration time: 10.001
一个多线程程序(传递对象方式创建线程):
# -*- coding: utf-8 -*
import threading
import time
people = 500 # 假设有500个人
def action(num):
global people
while people>0:
people -= 50 # 每次运输50人
print("车辆编号:%d, 当前车站人数:%d" %(num, people))
time.sleep(1)
start = time.time()
vehicles = [] # 新建车辆组
for num in range(5):
vehicle = threading.Thread(target=action, args=(num,)) # 新建车辆
vehicles.append(vehicle) # 添加车辆到车辆组中
for vehicle in vehicles:
vehicle.start() # 分别启动车辆
for vehicle in vehicles:
vehicle.join() # 分别检查到站车辆
end = time.time()
print("Duration time: %0.3f" % (end-start))
运行结果:
车辆编号:0, 当前车站人数:450
车辆编号:1, 当前车站人数:400
车辆编号:2, 当前车站人数:350
车辆编号:3, 当前车站人数:300
车辆编号:4, 当前车站人数:250
车辆编号:2, 当前车站人数:200
车辆编号:1, 当前车站人数:150
车辆编号:0, 当前车站人数:100
车辆编号:3, 当前车站人数:50
车辆编号:4, 当前车站人数:0
Duration time: 2.001
一个多线程程序(覆盖子类的方式):
# -*- coding: utf-8 -*
import threading
import time
people = 500
class MyThread(threading.Thread):
def __init__(self, num):
super(MyThread, self).__init__()
self.num = num
def run(self):
global people
while people > 0:
people -= 50
print("车辆编号:%d, 当前车站人数:%d " % (self.num, people))
time.sleep(1)
start = time.time()
vehicles = [] # 新建车辆组
for num in range(5): # 设置车辆数
vehicle = MyThread(num) # 新建车辆
vehicles.append(vehicle) # 添加车辆到车辆组中
vehicle.start() #启动车辆
for vehicle in vehicles:
vehicle.join() # 分别检查到站车辆
end = time.time()
print("Duration time: %0.3f" % (end-start))
结果:
车辆编号:0, 当前车站人数:450
车辆编号:1, 当前车站人数:400
车辆编号:2, 当前车站人数:350
车辆编号:3, 当前车站人数:300
车辆编号:4, 当前车站人数:250
车辆编号:0, 当前车站人数:200
车辆编号:2, 当前车站人数:150 车辆编号:3, 当前车站人数:100车辆编号:1, 当前车站人数:50
车辆编号:4, 当前车站人数:0
Duration time: 2.003
结果分析: ①通过显示结果可以发现,不使用线程的程序和使用单线程的程序运行时间是一样的,这是因为我们正常执行一个脚本,本质上就是单线程执行。
②创建多线程的两种方法运行时间也是一样的,因为最终都是交给thread类来处理,自行选择即可。
③多线程运行时间明显比单线快大概5倍,从理论上来说是和线程数成正比的,但是实际应用中并非线程越多就越好,因为线程越多消耗的资源也就越多。
注意:①创建线程对象后,必须通过调用线程的start()方法启动其活动,这将在单独的控制线程中调用run()方法
②一旦线程的活动开始,线程就是被认为是“活着的”,当run()方法终止时,它会停止活动,或者引发异常
③线程可以调用is_alive()方法测试是否处于活动状态,其他线程可以调用线程的join()方法,这将阻塞调用线程,直到调用其join()方法的线程终止
④线程有一个名称,这个名称可以传递给构造函数,并通过name属性读取或更改
⑤线程可以标记为“守护程序线程”,这个标志的意义在于,当只剩下守护进程线程时,整个Python程序都会推出,可以通过守护程序属性设置该标志
更多请看: https://www.cnblogs.com/leozhanggg/p/10335098.html