一、进程的PID号
1、作用:一台计算机上面同时会运行很多进程,PID号就是分配给每个进程来用于区分具体是哪个进程的。
2、终端查看PID号的指令:
①windows:tasklist---查看所有进程,tasklist | findstr PID---指定PID号查看具体进程。
②linux:ps aux---查看所有进程,ps aux | grep PID---指定PID号查看具体进程。
3、py程序中查看PID号:
import multiprocessing import os def task(): print('子进程号:{}'.format(os.getpid())) # 查看当前进程号 print('子进程号:{}'.format(multiprocessing.current_process().pid)) # 查看当前进程号,效果等同于上一条 print('主进程号:{}'.format(os.getppid())) # 查看当前进程的父进程号 if __name__ == '__main__': p = multiprocessing.Process(target=task) p.start() p.join() print('主进程号:{}'.format(os.getpid())) print('pycharm进程号:{}'.format(os.getppid())) ''' 结果为: 子进程号:12504 子进程号:12504 主进程号:8928 主进程号:8928 pycharm进程号:5888 '''
二、中止进程
import multiprocessing import time def task(): print('子进程开启了...') time.sleep(3) print('子进程结束了...') if __name__ == '__main__': p = multiprocessing.Process(target=task) p.start() time.sleep(0.1) p.terminate() # 中止子进程 time.sleep(0.1) print(p.is_alive()) # 判断子进程是否存活 ''' 结果为: 子进程开启了... False '''
三、僵尸进程与孤儿进程
1、僵尸进程:子进程被中止的瞬间不会立刻释放所占用的进程号,此时主进程依然可以看到它开设的子进程的一些基本信息,如PID号,运行时间等等,此时的子进程就称为僵尸进程。
2、孤儿进程:主进程已被中止,但子进程依然存活,此时的子进程就称为孤儿进程,操作系统会开设专门的机制用于管理孤儿进程来回收相关资源。
四、守护进程:伴随主进程的结束而同步中止的子进程就称为守护进程。
import multiprocessing import time def task(): print('子进程开启了...') time.sleep(3) print('子进程结束了...') if __name__ == '__main__': p = multiprocessing.Process(target=task) p.daemon = True # 声明子进程为守护进程 p.start() time.sleep(0.1) print('主进程结束了') ''' 结果为: 子进程开启了... 主进程结束了 '''
五、互斥锁:多个进程操作同一份数据的时候有可能会出现数据错乱的问题,为了解决这个现象,可以引用互斥锁的机制,但是如此就会把并发的进程转变成为串行,牺牲了效率而保证了数据的安全性和可靠性。
import multiprocessing import json import time import random def search(x): with open(r'E:\python之路\01 课程\week08-day04\03 博客整理\库存.json', 'rt')as f: stock_dict = json.load(f) print('{}号工作人员正在查询库存为:{}'.format(x, stock_dict.get('stock'))) # 先让用户查看库存 def get_out(x): with open(r'E:\python之路\01 课程\week08-day04\03 博客整理\库存.json', 'rt')as f: stock_dict = json.load(f) stock = stock_dict.get('stock') # 出库之前确认实际库存 if stock > 0: # 若有库存,则出库 stock -= 1 stock_dict['stock'] = stock with open(r'E:\python之路\01 课程\week08-day04\03 博客整理\库存.json', 'wt')as f: json.dump(stock_dict, f) print('{}号工作人员已成功出库'.format(x)) else: # 若无库存,则显示没有库存,出库 print('{}号工作人员出库失败,因为没有库存了'.format(x)) def run(x, mutex): # 给进程对象导入互斥锁参数 search(x) time.sleep(random.uniform(1, 2)) # 模拟网络延迟波动 mutex.acquire() # 在执行出库操作前先抢锁,只有抢到锁,才可以进行后续步骤 get_out(x) mutex.release() # 出库完毕则释放锁 if __name__ == '__main__': mutex = multiprocessing.Lock() # 主进程中生成互斥锁 for n in range(1, 6): p = multiprocessing.Process(target=run, args=(n, mutex)) p.start() ''' 结果为: 1号工作人员正在查询库存为:1 2号工作人员正在查询库存为:1 3号工作人员正在查询库存为:1 4号工作人员正在查询库存为:1 5号工作人员正在查询库存为:1 3号工作人员已成功出库 5号工作人员出库失败,因为没有库存了 1号工作人员出库失败,因为没有库存了 2号工作人员出库失败,因为没有库存了 4号工作人员出库失败,因为没有库存了 '''
六、通信队列:本质就是,管道+互斥锁,遵循“先进先出”的原则。
import multiprocessing q = multiprocessing.Queue(5) # 创建一个队列,声明队列最大容量 print(q.empty()) # 判断队列是否为空 q.put('111') q.put('222') q.put('333') q.put('444') q.put('555') print(q.full()) # 判断队列是否满载 # q.put('666') # 当队列满载后若继续加入数据,程序不会报错,会阻塞在原地,直到其他进程取走一个数据,再让本处数据能够顺利加入 v1 = q.get() v2 = q.get() v3 = q.get() v4 = q.get() v5 = q.get() # v6 = q.get() # 当取数据的队列取无可取数据时,程序也不会报错,会阻塞在原地,直到其他进程加入一个数据,再让本处能够顺利取走 # v6 = q.get_nowait() # 无数据可取则不再阻塞等待,直接报错 # v6 = q.get(timeout=3) # 无数据可取会等待3秒,之后若依然如此,再报错 try: # 用 try 语句既可以保证不阻塞,也可以避免报错 v6 = q.get(timeout=3) # 或用 v6 = q.get_nowait() except Exception as e: print('队列空了!')
七、IPC机制之生产者消费者模型:借助队列实现进程之间的通信
import multiprocessing import time import random def producer(name, goods, q): for n in range(1, 6): time.sleep(random.uniform(1, 2)) in_goods = '{}号产品{}'.format(n, goods) q.put(in_goods) print('{}生产了{}'.format(name, in_goods)) # 生产者循环产出数据加入队列中 def consumer(name, q): while 1: time.sleep(random.uniform(1, 2)) out_goods = q.get() print('{}取走了{}'.format(name, out_goods)) q.task_done() # 消费者循环从队列取走数据,每取一个,队列的可取值计数器会减1 if __name__ == '__main__': q = multiprocessing.JoinableQueue() p1 = multiprocessing.Process(target=producer, args=('林师傅', '茶叶蛋', q)) p2 = multiprocessing.Process(target=producer, args=('刘师傅', '火腿肠', q)) c1 = multiprocessing.Process(target=consumer, args=('小张', q)) c2 = multiprocessing.Process(target=consumer, args=('小李', q)) p1.start() p2.start() c1.daemon = True c2.daemon = True # 将消费者声明为守护进程,随主程序最后一条代码运行完毕自动终止 c1.start() c2.start() p1.join() p2.join() # 等待生产者生产完毕 q.join() # 当队列的可取数据为0才会执行到出最后一行代码,也是实现了队列可取数据为0代表程序该结束了,消费者无数据可取,自动消失