第十三节课:多线程
目录
一、 线程
线程也叫轻量级线程,是操作系统能够进行运算调度的最小单位,包含在进程中,是进程中实际运行单位。
二、为什么使用多线程:
多线程是多礼的并发的执行流,能够共享数据,文件,句柄和内存,不用开辟新的储存空间,比进程有更好的效率
三.线程的实现:threaing模块
1.自定义编程:
继承threading.Thread 重构run方法
2.守护线程:
子线程会随着主线程的结束而结束(不管子线程是否运行完)
主线程等待子线程的方法:.join
多线程共享全局变量:在同一个进程中多线程是共享资源的。
3.互斥锁:
多个线程同士修改统一数据是可能出现脏数据,为了防止这一情况,设计了互斥锁,同一时刻只允许一个线程执行操作
获取锁:lock.acquire()
释放锁:lock.release()
4.递归锁:
与lock一样,支持嵌套,在多个锁没有释放时,一般会使用RLcok类。
Lock = treading.RLock()
5.信号量:
一次性允许线程的数量
6.事件:
用于多线程(如同信号灯)控制其他线程(如同车)的执行,事件是一个简单的线程同步对象。
set:把flag设为True
clear:把flag设为False
is_set:判断是否设置了flag
wait:会一直监听flag,如果没有检测到flag就一直处于阻塞状态
四.GIL:全局解释器锁:
在pyth设计之初为了数据安全,无论多少核,同时只能执行一个线程。
五.补充:多进程的实现
import multiprocessing
import time
import os
# multiprocessing模块(标准)提供了一个Process类,用来表示进程对象 ☆
def child_1(interval):
print('1子进程%s开始执行,父进程是%s'%(os.getpid(),os.getppid()))
start_time = time.time()
time.sleep(interval)
end_time = time.time()
print('子进程%s结束执行,用时为%s'%(os.getpid(),end_time - start_time))
def child_2(interval):
print('2子进程%s开始执行,父进程是%s'%(os.getpid(),os.getppid()))
start_time = time.time()
time.sleep(interval)
end_time = time.time()
print('子进程%s结束执行,用时为%s'%(os.getpid(),end_time - start_time))
if __name__ == '__main__':
print('************************主进程开始******************************')
print('主进程的pid时%s'%os.getpid())
p1 = multiprocessing.Process(target=child_1,args=(2,))
p2 = multiprocessing.Process(target=child_2,args=(2,))
p1.start()
p2.start()
print('子进程1运行情况是:',p1.is_alive())
print('子进程2运行情况是:',p2.is_alive())
print('子进程1名字是',p1.name)
print('子进程2名字是',p2.name)
print('子进程1pid是',p1.pid)
print('子进程2pid是',p2.pid)
print('等待子进程结束')
p1.join()
p2.join()
print('主进程pid是%s'%os.getpid())
print('************************主进程结束******************************')
# 利用Process类的子类创建进程 ☆
# 通过定义一个类,使其继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象 ☆
# 注意:子类必须实现run方法(覆盖重写)
# 注意:子类必须调用父类的构造方法(用类型调用)
class SubProcess(multiprocessing.Process):
def __init__(self,interval,name=''):
multiprocessing.Process.__init__(self)
self.interval = interval
if name:
self.name = name
def run(self):
print('子进程%s开始,父进程是%s'%(os.getpid(),os.getppid()))
start_time = time.time()
time.sleep(self.interval)
end_time = time.time()
print('子进程%s结束,用时%s'%(os.getpid(),end_time-start_time))
if __name__ == '__main__':
print('父进程%s开始'% os.getpid())
p1 = SubProcess(1,'chile_01')
p2 = SubProcess(1,'chile_02')
p1.start()
p2.start()
print(p1.is_alive())
print(p2.is_alive())
print(p1.name,p1.pid)
print(p2.name,p2.pid)
p1.join()
p2.join()
print('父进程结束')
def task01():
time.sleep(0.5)
print('hello')
def task02():
time.sleep(0.5)
print('world')
if __name__ == '__main__':
print('父进程%s开始'%os.getpid())
p1 = multiprocessing.Process(target=task01)
p2 = multiprocessing.Process(target=task02)
p1.daemon = True
p2.daemon = True
p1.start()
p2.start()
time.sleep(1)
print('父进程结束')
#上锁
def tack01(lock,f):
with lock:
n = 10
while n>0:
with open(f,'a+') as file:
file.write('task01 hello world\n')
n -=1
print(111)
time.sleep(0.2)
# 关于Lock锁:☆
# 应用场景:当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突
def tack02(lock,f):
with lock:
n = 10
while n>0:
with open(f,'a+') as file:
file.write('task02 hi python\n')
n -=1
print(222)
time.sleep(0.2)
if __name__ == '__main__':
lock = multiprocessing.Lock()
f = 'demo.txt'
p1 = multiprocessing.Process(target=tack01,args=(lock,f))
p2 = multiprocessing.Process(target=tack02,args=(lock,f))
p1.start()
p2.start()
p1.join()
p2.join()
print('end')
#信号量
def worker(s):
s.acquire()#获取
print(str(os.getpid())+'acquire')
time.sleep(1)
print(str(os.getpid()) + 'release')
s.release()#释放
if __name__ == '__main__':
s = multiprocessing.Semaphore(3) #规定信号量(一次能有几个进程)
for i in range(1,7):
multiprocessing.Process(target=worker,args=(s,)).start()
print('end')
# 关于进程池Pool:
# 应用场景:如果需要创建几十个或上百个进程,就需要实例化更多的Process类或其子类
# 那么如何解决这个麻烦事呢?可以使用multiprocessing模块里的Pool类(进程池)
def ttask():
print('子进程%s开始'%os.getpid())
time.sleep(1)
if __name__ == '__main__':
print('父进程%s开始'%os.getpid())
pool = multiprocessing.Pool(3)
for i in range(10):
pool.apply_async(ttask)
# pool.apply(ttask)
pool.close()
pool.join()
print('父进程结束')
# 进程间的通信:
# 每个进程都有自己独立的地址空间、内存、数据栈以及其他记录运行状态的辅助数据 ☆
# 正常情况下,进程间是无法通信的:
num = 100
def fun1():
print('子进程1开始')
global num
num+=50
print(num)
print('子进程1结束')
def fun2():
print('子进程2开始')
global num
num-=50
print(num)
print('子进程2结束')
if __name__ == '__main__':
print('父进程开始')
print(num)
p1 = multiprocessing.Process(target=fun1)
p2 = multiprocessing.Process(target=fun2)
p1.start()
p2.start()
p1.join()
p2.join()
print('父进程结束')
# 问题:那么如何进行进程间的通信呢?使用队列 ☆
# 关于队列:Queue ☆(multiprocessing模块里)
# 1)队列:就是模拟现实中的排队 ☆
# 2)队列的特点:先进先出 ☆
q = multiprocessing.Queue(3)
q.put('xiao1')
q.put('xiao2')
print(q.full())
q.put('xiao3')
print(q.full())
q.put('xiao4')#进入阻塞状态
q.put('xiao4',False)#只要满了就报异常
q.put('xiao4',True,2)#只要满了,等两秒,两秒后还是满的就报异常
try:
q.put('xiao4',False)
except:
print('队列已满')
if not q.empty():#如果队列不是空
print('从队列中获取信息:')
for i in range(q.qsize()):
print(q.get())
# 使用队列实现进程间通信:☆
def w(q):
if not q.full():
for i in range(5):
q.put('消息'+str(i))
print('写入数据'+str(i))
def r(q):
time.sleep(1)
while not q.empty():
print('读出'+q.get())
if __name__ == '__main__':
q = multiprocessing.Queue(5)
pw = multiprocessing.Process(target=w,args=(q,))
pr = multiprocessing.Process(target=r,args=(q,))
pw.start()
pr.start()