线程介绍
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
使用多线程是为了提高程序的运行效率
线程实现
使用threading模块
普通创建方式
# 导入threading模块
import threading
# 定义一个函数
def add(x,y):
print(x + y)
# 新建一个线程
t = threading.Thread(target=add, args=(1,2,))
# 线程启动
t.start()
结果为3
自定义线程
继承threading.Thread来自定义线程类,其本质是重构Thread类中的run方法
import threading
class MyThread(threading.Thread):
def __init__(self,x,y):
super(MyThread, self).__init__() # 重构run函数必须要写
self.x = x
self.y = y
def run(self):
print(self.x + self.y)
t = MyThread(1,2)
t.start()
结果还是3
守护线程
我们看下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,因此当主进程结束后,子线程也会随之结束。所以当主线程结束后,整个程序就退出了。
# 导入threading模块
import threading
# 定义一个函数
def add(x,y):
print(x + y)
# 新建一个线程
t = threading.Thread(target=add, args=(1,2,))
t.setDaemon(True) #把子进程设置为守护线程,必须在start()之前设置
# 线程启动
t.start()
主线程等待子线程结束
# 导入threading模块
import threading
# 定义一个函数
def add(x,y):
print(x + y)
# 新建一个线程
t = threading.Thread(target=add, args=(1,2,))
# 线程启动
t.start()
t.join() # 设置主线程等待子线程结束
多线程共享全局变量
# 导入threading模块
import threading
import time
g_num = 1
# 定义一个函数
def add1(num):
global g_num
g_num = g_num + num
print(g_num)
def add2(num):
global g_num
g_num = g_num + num
print(g_num)
# 新建一个线程#
t1 = threading.Thread(target=add1, args=(1,))
t2 = threading.Thread(target=add2, args=(2,))
# 线程启动
t1.start()
#延时一会,保证t1线程中的事情做完
time.sleep(1)
t2.start()
结果为:
2
4
互斥锁
当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源
导入线程模块,通过threading.Lock()
创建互斥锁.
里面有两个方法
acquire()
— 锁定资源,此时资源是锁定状态,其他线程无法修改锁定的资源,直到等待锁定的资源释放之后才能操作;
release()
— 释放资源,也称为解锁操作,对锁定的资源解锁,解锁之后其他线程可以对资源正常操作;
# 导入threading模块
import threading
import time
# 声明全局变量
g_num = 1
# 创建互斥锁
lock = threading.Lock()
# 定义一个函数
def add1():
global g_num
for i in range(0,100):
# 锁定资源
lock.acquire()
g_num = g_num + 1
# 解锁资源
lock.release()
print(g_num)
def add2():
global g_num
for i in range(0,100):
# 锁定资源
lock.acquire()
g_num = g_num + 1
# 解锁资源
lock.release()
print(g_num)
# 新建一个线程
t1 = threading.Thread(target=add1)
t2 = threading.Thread(target=add2)
# 线程启动
t1.start()
t2.start()
# 阻塞函数,等待线程结束
t1.join()
t2.join()
结果:
100
200
信号量(BoundedSemaphore类)
互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据
import threading
import time
bs = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行
def run(n):
bs.acquire() #加锁
time.sleep(1)
print("run the thread:%s\n" % n)
bs.release() #释放
for i in range(0,20):
t = threading.Thread(target=run, args=(i,))
t.start()
运行结果发现是5个线程5个线程的打印
事件(Event类)
- clear 将flag设置为“False”
- set 将flag设置为“True”
- is_set 判断是否设置了flag
- wait 会一直监听flag,如果没有检测到flag就一直处于阻塞状态
事件处理的原理:全局定义了一个Flag
,当flag值为False
,那么event.wait()就会阻塞,当flag值为True
,那么event.wait()便不再阻塞。
import threading
import time
event = threading.Event()
def before():
print("准备工作")
event.set() # 设置开始工作
time.sleep(5)
event.clear()
def work():
if event.is_set():#判断是否设置了标志位
while 1:
event.wait()
print("工作中!!!")
time.sleep(1)
if event.wait(3):
pass
else:
print("工作结束")
break
before = threading.Thread(target=before,)
work = threading.Thread(target=work,) before.start()
work.start()
before.join()
work.join()
结果:
其它的方法
threading方法
方法 | 功能 |
---|---|
active_count() , activeConut() | 返回处于alive状态的Thread对象数量 |
current_thread() , currentThread() | 返回当前的Thread对象 |
get_ident() | 返回当前线程的线程标识符。线程标识符是一个非负整数,并无特殊函数,只是用来标识线程,该整数可能会被循环利用。python3.3及以后版本支持该方法 |
enumerate() | 返回当前处于alive状态的所有Thread对象列表 |
stack_size([size]) | 返回创建线程时使用的栈的大小,如果指定size参数,则用来指定后续创建的线程使用的栈大小,size必须是0(表示使用系统默认值)或大于32K的正整数。 |
main_thread() | 返回主线程对象,即启动python解释器的线程对象。python3.4及以后版本支持该方法 |