-
僵尸进程和孤儿进程(基于UNIX环境:linux,macos)
-
僵尸进程:所有的子进程结束之后,在被主进程回收之前,都会进入僵尸进程状态
1. 主进程需要等待子进程结束之后,主进程才结束 2. 主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间之内将子进程进行回收
from multiprocessing import Process import time import os def task(name): print(f'{name} is running') print(f'主进程:{os.getppid()}') print(f'子进程:{os.getpid()}') time.sleep(50) print(f'{name} is gone') if __name__ == '__main__': p = Process(target=task,args=('长兴',)) p.start() print('===主开始') 主进程等待子进程结束之后,主进程结束
- 为什么主进程不在子进程结束后马上对其回收呢
1.主进程和子进程是异步关系,主进程无法马上捕获子进程什么时候结束 2.如果子进程结束之后马上在内存中释放资源,主进程就没有办法监测子进程的状态了
- Unix针对上面的问题,提供了一个机制
所有的子进程结束之后,立马会释放掉文件的操作链接,内存的大部分数据,但是会保留一些内容:进程号,结束时间,运行状态,等待主进程监测,回收
- 僵尸进程的危害
如果父进程不对僵尸进程进行回收(wait、waitpid),产生大量的僵尸进程,这样就会占用内存,占用进程pid号
-
孤儿进程:
父进程由于某种原因结束了,但是你的子进程还在运行中,这样你的这些子进程就成了孤儿进程,你的父进程如果结束了,你的所有孤儿进程就会被init进程回收,init就会变成你的父进程,对子进程进行回收。
- 僵尸进程如何解决?
父进程产生了大量的子进程,但是不回收,这样就会形成大量的僵尸进程,解决方法就是直接杀死父进程,将所有的僵尸进程变成孤儿进程,由init进行回收
-
-
互斥锁
举例: 三个同事,同时用一个打印机打印内容
三个进程模拟三个同事,输出平台模拟打印机
# 版本一: # from multiprocessing import Process # import time # import random # import os # # def task1(): # print(f'{os.getpid()}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}打印结束了') # # def task2(): # print(f'{os.getpid()}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}打印结束了') # # def task3(): # print(f'{os.getpid()}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{os.getpid()}打印结束了') # # if __name__ == '__main__': # # p1 = Process(target=task1) # p2 = Process(target=task2) # p3 = Process(target=task3) # # p1.start() # p2.start() # p3.start() # 现在是所有的进程都并发的抢占打印机, # 并发是以效率优先的,但是目前我们的需求: 顺序优先. # 多个进程共强一个资源时, 要保证顺序优先: 串行,一个一个来. # 版本二: # from multiprocessing import Process # import time # import random # import os # # def task1(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # def task2(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # def task3(p): # print(f'{p}开始打印了') # time.sleep(random.randint(1,3)) # print(f'{p}打印结束了') # # if __name__ == '__main__': # # p1 = Process(target=task1,args=('p1',)) # p2 = Process(target=task2,args=('p2',)) # p3 = Process(target=task3,args=('p3',)) # # p2.start() # p2.join() # p1.start() # p1.join() # p3.start() # p3.join() # 我们利用join 解决串行的问题,保证了顺序优先,但是这个谁先谁后是固定的. # 这样不合理. 你在争抢同一个资源的时候,应该是先到先得,保证公平.
版本三: from multiprocessing import Process from multiprocessing import Lock import time import sys import random def task1(p,lock): lock.acquire() print(f'{p}打印开始了') time.sleep(random.randint(1,3)) print(f'{p}打印结束了') lock.release() def task2(p,lock): lock.acquire() print(f'{p}打印开始了') time.sleep(random.randint(1,3)) print(f'{p}打印结束了') lock.release() def task3(p,lock): lock.acquire() print(f'{p}打印开始了') time.sleep(random.randint(1,3)) print(f'{p}打印结束了') lock.release() if __name__ =='__main__': mutex = Lock() for i in range(1,4): p = Process(target = getattr(sys,modules[__name__],f'task{i}'),args = (f'p{i}',mutex)) p.start()
- lock和join的区别
共同点:都可以把并发变成串行,保证了顺序 不同点:join人为设定顺序,lock让其争抢顺序,保证了公平性
-
进程之间的通信
-
基于文件的通信
抢票系统. # 1. 先可以查票.查询余票数. 并发 # 2. 进行购买,向服务端发送请求,服务端接收请求,在后端将票数-1,返回到前端. 串行. # from multiprocessing import Process # import json # import time # import os # import random # # # def search(): # time.sleep(random.randint(1,3)) # 模拟网络延迟(查询环节) # with open('ticket.json',encoding='utf-8') as f1: # dic = json.load(f1) # print(f'{os.getpid()} 查看了票数,剩余{dic["count"]}') # # # def paid(): # with open('ticket.json', encoding='utf-8') as f1: # dic = json.load(f1) # if dic['count'] > 0: # dic['count'] -= 1 # time.sleep(random.randint(1,3)) # 模拟网络延迟(购买环节) # with open('ticket.json', encoding='utf-8',mode='w') as f1: # json.dump(dic,f1) # print(f'{os.getpid()} 购买成功') # # def task(): # search() # paid() # # # if __name__ == '__main__': # # for i in range(6): # p = Process(target=task) # p.start() # 当多个进程共强一个数据时,如果要保证数据的安全,必须要串行. # 要想让购买环节进行串行,我们必须要加锁处理. # # from multiprocessing import Process # from multiprocessing import Lock # import json # import time # import os # import random # # # def search(): # time.sleep(random.randint(1,3)) # 模拟网络延迟(查询环节) # with open('ticket.json',encoding='utf-8') as f1: # dic = json.load(f1) # print(f'{os.getpid()} 查看了票数,剩余{dic["count"]}') # # # def paid(): # with open('ticket.json', encoding='utf-8') as f1: # # dic = json.load(f1) # if dic['count'] > 0: # dic['count'] -= 1 # time.sleep(random.randint(1,3)) # 模拟网络延迟(购买环节) # with open('ticket.json', encoding='utf-8',mode='w') as f1: # json.dump(dic,f1) # print(f'{os.getpid()} 购买成功') # # # def task(lock): # search() # lock.acquire() # paid() # lock.release() # # if __name__ == '__main__': # mutex = Lock() # for i in range(6): # p = Process(target=task,args=(mutex,)) # p.start() # 当很多进程共强一个资源(数据)时, 你要保证顺序(数据的安全),一定要串行. # 互斥锁: 可以公平性的保证顺序以及数据的安全. # 基于文件的进程之间的通信: # 效率低. # 自己加锁麻烦而且很容易出现死锁. # dic = {'name': 'alex'} # import json # print(json.dumps(dic))
-
基于队列的通信
-
队列:一个可以承载数据的容器,先进先出永远保持这个数据
-
q = Queue(3) 设置队列里的数据数,满了就会阻塞,当数据取完,在进程get数据也会出现阻塞,直到某一个进程put数据
-
q.get(timeout = 3) )阻塞3秒,3秒之后还阻塞直接报错
-
block = False 只要遇到阻塞就会报错
q.put(555,block = False) q.get(block = False)
队列: 把队列理解成一个容器,这个容器可以承载一些数据, # 队列的特性: 先进先出永远保持这个数据. FIFO 羽毛球筒. # from multiprocessing import Queue # q = Queue() # def func(): # print('in func') # q.put(1) # q.put('alex') # q.put([1,2,3]) # q.put(func) # # # print(q.get()) # print(q.get()) # print(q.get()) # f = q.get() # f() # from multiprocessing import Queue # q = Queue(3) # # q.put(1) # q.put('alex') # q.put([1,2,3]) # # q.put(5555) # 当队列满了时,在进程put数据就会阻塞. # # q.get() # # print(q.get()) # print(q.get()) # print(q.get()) # print(q.get()) # 当数据取完时,在进程get数据也会出现阻塞,直到某一个进程put数据. from multiprocessing import Queue q = Queue(3) # maxsize q.put(1) q.put('alex') q.put([1,2,3]) # q.put(5555,block=False) # print(q.get()) print(q.get()) print(q.get()) print(q.get(timeout=3)) # 阻塞3秒,3秒之后还阻塞直接报错. # print(q.get(block=False)) # block=False 只要遇到阻塞就会报错. # 第一个作业: 将抢票系统变成队列方式完成.
-
-