善用搜索

python35 1.守护进程 2.互斥锁3.IPC 4.生产者和消费者模型教程

复习<br></br>1.TCP粘包问题<br></br>2.UDP<br></br>3.进程<br></br>    1.TCP粘包问题<br></br>    2.UDP<br></br>        区别:<br></br>        UDP 不粘包,不可靠,效率高,适合数据量小的传输,不要求顺序,不需要建立连接<br></br>        使用场景:<br></br>        UDP 适用于,对速度要求高,但是对数据完整性要求不高,DNS,对战游戏<br></br><br></br>    网络编程:目前的  无法并发处理多个客户端<br></br><br></br>进程<br></br>    一个正在运行的程序称之为进程<br></br>    进程来自于操作系统<br></br>    在第三代操作系统中,诞生了多道技术<br></br>    多道技术 是为了提高计算机资源的利用率,第三代以前是串行执行任务的批处理方式<br></br>    空间复用<br></br>        同一时间在内存中存储多个程序的数据<br></br>        内存区域要相互隔离,物理隔离,你是不可能随意访问的<br></br>    时间复用<br></br>        切换+保存<br></br>        当一个进程遇到了IO操作时,就切换其他进程来执行,切换前要记录当前运行状态<br></br>        切换条件:<br></br>            遇到了IO<br></br>            运行时间过长,时间片用完了<br></br><br></br>    什么时候要开启进程<br></br>        当有一个任务,执行时间过长时,为了提高效率,我们就可以将这个任务交给子进程来完成<br></br>    linux 与windows开启子进程的区别<br></br>        linux 会把数据完整copy给子进程 ,作为子进程的初始状态<br></br>        windows 会重新导入父进程的代码来获取需要数据,这样一来创建进程的代码又被执行了一次,造成递归创建进程<br></br>            所以要将开启子进程的代码放到 if __name__ == "__main__":中 保证创建进程的代码只被父进程执行<br></br>    如何开启子进程<br></br>        1.导入 multiprocessing 中的 Process<br></br>            实例化Process类 用target来指定要执行任务函数<br></br>            调用start来开启进程<br></br>        2.创建一个类,继承Process,覆盖run方法,将任务代码放到run中<br></br><br></br>    进程之间内存相互隔离<br></br><br></br>    僵尸进程 有害<br></br>        子进程结束了,父进程还在运行,子进程会占用pid 并且将保留最后的运行状态在内存中<br></br>        在linux中 父进程需要调用wait/waitpid来获取子进程的残留信息,并清理它<br></br>        python中已经封装好了 wait 操作不需要我们自己来清理<br></br><br></br>        如果出现很多僵尸进程<br></br>        清除僵尸进程的方法就是 杀死父进程<br></br><br></br>    孤儿<br></br>        父进程已经挂了 ,子进程还在运行,会被移交给操作系统来管理<br></br><br></br>    常用属性:<br></br>        join  父进程等待子进程运行结束   其实是提高子进程的优先级<br></br>        is_alive 是否存活<br></br>        getpid 获取自己的进程id<br></br>        name 进程的名字<br></br>        daemon<br></br>        terminate  终止这个子进程    有延迟<br></br>        start  启动进程  有延迟<br></br>        因为开启和关闭进程 都是操作系统来完成<br></br><br></br>    进程的状态<br></br>        运行 -io>  阻塞  -> 就绪态<br></br>        运行 -时间片用完了(运行时间过长)>  就绪态<br></br><br></br>    阻塞<br></br>        当程序遇到了IO操作,就进入了阻塞态<br></br>    非阻塞<br></br>        程序正在运行中,没有任何IO操作<br></br>    指的是程序的运行状态<br></br><br></br>    并行<br></br>       多个程序同时运行,是真正的同时执行,仅在多核中会出现<br></br><br></br>    并发<br></br>        多个事件同时发生了,看起来像是都在运行,本质上是切换执行<br></br><br></br>    程序员永恒的话题<br></br>        提高程序的效率  减少IO 力求尽可能多占用CPU

今日内容: 1.守护进程 2.互斥锁 3.IPC 4.生产者和消费者模型 1.守护进程 了解 什么是守护进程 ​ 进程是一个正在运行的程序 ​ 守护进程也是一个普通进程 ​ 意思是一个进程可以守护另一个进程 例如 ​ 康熙要是一个进程的话,后宫佳丽都是守护者 ​ 如果康熙挂了, 后宫佳丽们要陪葬 结论: 如果b是a的守护进程,a是被守护的进程,a要是挂了,b也就随之结束了 测试: `python
from multiprocessing import Process
import time # 妃子的一生
def task():
print("入宫了.....")
time.sleep(50)
print("妃子病逝了......")
if \_\_name\_\_ == '\_\_main\_\_':
# 康熙登基了
print("登基了.....") # 找了一个妃子
p = Process(target=task) # 设置为守护进程 必须在开启前就设置好
p.daemon = True
p.start() # 康熙驾崩了
time.sleep(3)
print("故事结束了!")

当多个进程同时要操作同一个资源时,将会导致数据错乱的问题  
如下列所示: 解决方案1: ​ 加join,  
​ 弊端 1.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了  
​ 2.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的 解决方案2: ​ 就是给公共资源加锁,互斥锁  
​ 互斥锁 互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了) 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行 #### 锁和join的区别:  
​ 1. ​ join是固定了执行顺序,会造成父进程等待子进程  
​ 锁依然是公平竞争谁先抢到谁先执行,父进程可以做其他事情 ​ 2.最主要的区别:  
​ join是把进程的任务全部串行  
​ 锁可以锁任意代码 一行也可以 可以自己调整粒度   
\### 案例:   
from multiprocessing import Process,Lock  
import time,random def task1(lock):  
 # 要开始使用了 上锁  
 lock.acquire() #就等同于一个if判断  
 print("hello iam jerry")  
 time.sleep(random.randint(0, 2))  
 print("gender is boy")  
 time.sleep(random.randint(0, 2))  
 print("age is 15")  
 # 用完了就解锁  
 lock.release() def task2(lock):  
 lock.acquire()  
 print("hello iam owen")  
 time.sleep(random.randint(0,2))  
 print("gender is girl")  
 time.sleep(random.randint(0,2))  
 print("age is 48")  
 lock.release() def task3(lock):  
 lock.acquire()  
 print("hello iam jason")  
 time.sleep(random.randint(0,2))  
 print("gender is women")  
 time.sleep(random.randint(0,2))  
 print("age is 26")  
 lock.release() if \_\_name\_\_ == '\_\_main\_\_':  
 lock = Lock() p1 = Process(target=task1,args=(lock,))  
 p2 = Process(target=task2,args=(lock,))  
 p3 = Process(target=task3,args=(lock,)) p1.start()  
 # p1.join() p2.start()  
 # p2.join() p3.start()  
 # p3.join() # print("故事结束!")  
   
\# 锁的伪代码实现 # if my\_lock == False:  
\# my\_lock = True  
\# #被锁住的代码  
 my\_lock = False 解锁 ``` 注意1: 不要对同一把执行多出acquire 会锁死导致程序无法执行 一次acquire必须对应一次release   
 l = Lock()  
 l.acquire()  
 print("抢到了!")  
 l.release()  
 l.acquire()  
 print("强哥毛线!")  
``` 注意2:想要保住数据安全,必须保住所有进程使用同一把锁 3.IPC ​ 进程间通讯 ​ 通讯指的就是交换数据 ​ 进程之间内存是相互隔离的,当一个进程想要把数据给另外一个进程,就需要考虑IPC 方式: ​ 管道: 只能单向通讯,数据都是二进制 ​ 文件: 在硬盘上创建共享文件 ​ 缺点:速度慢 ​ 优点:数据量几乎没有限制 ​ socket: ​ 编程复杂度较高 ​ 共享内存:必须由操作系统来分配 要掌握的方式\*\*\*\*\* ​ 优点: 速度快 ​ 缺点: 数据量不能太大 ## 共享内存的方式 ## 1.Manager类 了解 ​ Manager提供很多数据结构 list dict等等 ​ Manager所创建出来的数据结构,具备进程间共享的特点 ```python  
from multiprocessing import Process,Manager,Lock  
import time   
def task(data,l):  
 l.acquire()  
 num = data\["num"\] #  
 time.sleep(0.1)  
 data\["num"\] = num - 1  
 l.release() if \_\_name\_\_ == '\_\_main\_\_':  
 # 让Manager开启一个共享的字典  
 m = Manager()  
 data = m.dict({"num":10}) l = Lock() for i in range(10):  
 p = Process(target=task,args=(data,l))  
 p.start() time.sleep(2)  
 print(data)  
``` ​ 需要强调的是 Manager创建的一些数据结构是不带锁的 可能会出现问题 ## 2.Queue队列 帮我们处理了锁的问题 重点 ​ 队列是一种特殊的数据结构,先存储的先取出 就像排队 先进先出 ​ 相反的是堆栈,先存储的后取出, 就像衣柜 桶装薯片 先进后出 ​ 扩展: ​ 函数嵌套调用时 执行顺序是先进后出 也称之为函数栈 ​ 调用 函数时 函数入栈 函数结束就出栈 ```python  
from multiprocessing import Queue  
\# 创建队列 不指定maxsize 则没有数量限制  
q = Queue(3)  
\# 存储元素  
\# q.put("abc")  
\# q.put("hhh")  
\# q.put("kkk") # print(q.get())  
\# q.put("ooo") # 如果容量已经满了,在调用put时将进入阻塞状态 直到有人从队列中拿走数据有空位置 才会继续执行 #取出元素  
\# print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态 直到有人从存储了新的数据到队列中 才会继续 # print(q.get())  
\# print(q.get())   
\#block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列为空时 抛出异常  
q.get(block=True,timeout=2)  
\# block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列满了时 抛出异常  
\# q.put("123",block=False,)  
\# timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常 仅在block为True有效  

def eat(q):
for i in range(10):
# 要消费
rose = q.get()
time.sleep(random.randint(0, 2))
print(rose,"吃完了!") # 生产任务
def make\_rose(q):
for i in range(10):
# 再生产
time.sleep(random.randint(0, 2))
print("第%s盘青椒肉丝制作完成!" % i)
rose = "第%s盘青椒肉丝" % i
# 将生成完成的数据放入队列中
q.put(rose) if \_\_name\_\_ == '\_\_main\_\_':
# 创建一个共享队列
q = Queue()
make\_p = Process(target=make\_rose,args=(q,))
eat\_p = Process(target=eat,args=(q,))
make\_p.start()
eat\_p.start()

发表评论
退出移动版