day 29
day 29 进程互斥锁、队列、进程间通信、线程
01.进程互斥锁
-
可以让并发变成串行,牺牲了执行效率保证了数据安全
-
from multiprocessing import Lock mutex = Lock() # 创建一个锁对象 mutes.acquire() # 加锁 '''需要进程串行的功能,多为对数据的修改操作''' mutes.release() # 释放锁
-
在程序并发执行时,需要修改数据时使用
02.队列
-
相当于内存中的一个空间,可以存放多个数据,队列数据顺序为先到先排到前面,先进先出
-
堆栈;最先进来的最后出去
-
from multiprocessing import Queue q=Queue(5) # 表示队列中可以存放5个数据 q=Queue() # 不传参表示可以存放无限多的数据,硬件支持下的最大值
-
q.put(数据) # 添加数据,若队列中的数据满了则等待空位出现 q.empty() # 判断队列是否为空 q.get() # 从队列中获取数据,若对列中为空,则等待数据 q.get_mowait() # 同样是获取数据,若没有则报错 q.full() # 判断队列是否满了 q.put_mowait() # 同样是添加数据,队列如果满了则报错
-
pass
03.IPC 进程间通信
-
进程间数据是隔离的,可以通过队列进行通信
-
from multiprocessing import Process from multiprocessing import Queue def test1(q): data='数据' q.put(data) print('进程1向队列中添加数据') def test2(q): data=q.get() print(data) if __name__ == '__main__': q=Queue() # 创建一个队列 p1=Process(target=test1,args=(q,)) p2=Process(target=test2,args=(q,)) p1.start() p2.start() p2.join() print('主')
04.生产者与消费者
-
生产者;生产数据的
-
消费者;使用数据的
-
在程序中,生产者将数据放入队列中,消费者从队列中获取数据
-
from multiprocessing import Process from multiprocessing import Queue import time def producer(name, food, q): for i in range(9): data = food, i + 1 print(f'用户{name}制作{data}') q.put(data) time.sleep(0.5) def consumer(name, q): while True: data = q.get() if not data: break print(f'用户{name}食用{data}') if __name__ == '__main__': q = Queue() p1 = Process(target=producer, args=('logan', '牛肉干', q)) c1 = Process(target=consumer, args=('tank', q)) c2 = Process(target=consumer, args=('nick', q)) p1.start() c1.daemon = True c2.daemon = True c1.start() c2.start() p1.join() print('主')
05.线程
-
线程与进程都是虚拟单位,为了更好的描述某种事物
-
进程;资源单位
-
线程;执行单位
-
线程之间数据是共享的
-
开启一个进程一定会有一个线程,线程才是真正的执行者
-
为什么要使用线程;节省内存资源
- 开启进程;
- 开辟一个名称空间;没开启一个进程都会占用一份内存资源
- 会自带一个线程
- 开启线程
- 一个进程可以开启多个线程
- 线程的开销远小于进程
- 线程不能实现并行,只能实现并发
- 开启进程;
-
# 创建线程的方法一 from threading import Thread import time def test1(name): print(f'线程{name}开启') time.sleep(1) print(f'线程{name}结束') if __name__ == '__main__': t1 = Thread(target=test1, args=(1,)) t2 = Thread(target=test1, args=(2,)) t1.daemon = True t2.daemon = True t1.start() t2.start() time.sleep(3) print('主') # 方法二 自定义类 from threading import Thread import time class MyThread(Thread): def run(self): print('线程开始') time.sleep(1) print('线程结束') if __name__ == '__main__': t=MyThread() t.start() t.join() print('主')
-
线程对象的属性
-
t.isAlive() # 判断该进程是否存活 t.is_alive() # 判断该进程是否存活 t.getName() # 获取当前线程号 current_thread().name # 获取当前线程号 t.daemon = True # 守护线程,只要主线程结束,该子线程也跟着结束 t.isDaemon() # 判断该进程是否为守护进程
-
线程互斥锁 # 与进程互斥锁完全相同
-
from threading import Thread from threading import Lock import time mutex = Lock() # 创建一个锁对象 n=100 # 子线程是可以修改主线程的数据的 def tast(i): print(f'线程{i}启动') global n # 使函数内的n变为全剧变量 # mutex.acquire() # 上锁 nj=n time.sleep(0.1) # 模拟网络延迟,让进程等待0.1秒,使下一个进程获取到的n为未修改前的n n=nj-1 print(n) # mutex.release() # 开锁 if __name__ == '__main__': t_lis=[] for i in range(30): t=Thread(target=tast,args=(i,)) t_lis.append(t) t.start() # t.join() for i in t_lis: i.join() print('主')