进程(守护进程--互斥锁--IPC机制--生产者模型--僵尸进程与孤儿进程--模拟抢票--消息队列)
一:进程理论知识
- 顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。
进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之
一。操作系统的其他所有内容都是围绕进程的概念展开的。
1.理论知识
1.操作系统的作用:
1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2:管理、调度进程,并且将多个进程对硬件的竞争变得有序
2.多道技术:
1.产生背景:针对单核,实现并发
ps:
现在的主机一般是多核,那么每个核都会利用多道技术
有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
cpu中的任意一个,具体由操作系统调度算法决定。
2.空间上的复用:如内存中同时有多道程序
3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
才能保证下次切换回来时,能基于上次切走的位置继续运行
二:什么是进程?
- 狭义定义:进程是正在运行的程序的实例
- 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
三:僵尸进程与孤儿进程
1.僵尸进程
进程代码运行结束之后并没有直接结束而是需要等待回收子进程资源才能结束
from multiprocessing import Process
import time
def test(name):
print('%s is running' % name)
time.sleep(3)
print('%s is over' % name)
if __name__ == '__main__':
p = Process(target=test, args=('jason',))
p.start()
print('主')
- 孤儿进程
即主进程已经死亡(非正常)但是子进程还在运行 (子进程没有长辈)
from multiprocessing import Process
import time
def test(name):
print('%s is running' % name)
time.sleep(3)
print('%s is over' % name)
if __name__ == '__main__':
while True:
p = Process(target=test, args=('jason',))
p.start()
四:守护进程
1.什么是守护进程?
1.守护进程会随着主进程的结束而结束
2.主进程需要等待里面所有非守护进程的结束才能结束
主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
- 详细守护进程与守护线程区别:https://www.cnblogs.com/goOJBK/p/15806897.html
2.主进程创建守护进程
- 其一:守护进程会在主进程代码执行结束后就终止
- 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
- 守护进程:即守护着某个进程 一旦这个进程结束那么也随之结束
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止
3.守护进程
from multiprocessing import Process
import time
def test(name):
print('总管:%s is running' % name)
time.sleep(3)
print('总管:%s is over' % name)
if __name__ == '__main__':
p = Process(target=test, args=('jason',))
p.daemon = True # 设置为守护进程(一定要放在start语句上方)
p.start()
print("皇帝jason寿终正寝")
time.sleep(0.1)
五:互斥锁(模拟多人抢票)
1.什么是是锁?
锁就可以实现将并发变成串行的效果
行锁、表锁
2.什么是互斥锁?
互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作。
互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程需要等待,等互斥锁使用完释放后,其它等待的线程再去抢这个锁。
3.为什么要使用互斥锁?
通过执行结果可以地址互斥锁能够保证多个线程访问共享数据不会出现数据错误问题
操作同一份数据不能并发,并发情况下操作同一份数据 极其容易造成数据错乱
互斥锁对共享数据进行锁定,保证同一时刻只能有一个线程去操作。
4.常见问题
问题:并发情况下操作同一份数据 极其容易造成数据错乱
解决措施:将并发变成串行 虽然降低了效率但是提升了数据的安全
5.注意
- 使用锁的注意事项:
在主进程中产生 交由子进程使用
- 1.一定要在需要的地方加锁 千万不要随意加
- 2.不要轻易的使用锁(死锁现象)
6.Lock模块
Lock变量,这个变量本质上是一个函数,通过调用这个函数可以获取一把互斥锁
7.互斥锁(模拟多人抢票)
- 买票系统流程图
加上互斥锁多任务瞬间变成单任务,性能会下降,也就是说同一时刻只能有一个线程去执行
import json
from multiprocessing import Process, Lock
import time
import random
# 查票
def search(name):
with open(r'data.txt', 'r', encoding='utf8') as f:
data_dict = json.load(f)
ticket_num = data_dict.get('ticket_num')
print('%s查询余票:%s' % (name, ticket_num))
# 买票
def buy(name):
# 先查票
with open(r'data.txt', 'r', encoding='utf8') as f:
data_dict = json.load(f)
ticket_num = data_dict.get('ticket_num')
# 模拟一个延迟(选座) 随机魔魁啊
time.sleep(random.random())
# 判断是否有票
if ticket_num > 0:
# 买票 将余票减一
data_dict['ticket_num'] -= 1
# 重新写入数据库
with open(r'data.txt', 'w', encoding='utf8') as f:
json.dump(data_dict, f)
print('%s: 购买成功' % name)
else:
print('不好意思 没有票了!!!')
def run(name,mutex):
search(name)
mutex.acquire() # 抢锁/上锁 (一次只有一个人可以通过)
buy(name)
mutex.release() # 释放锁
if __name__ == '__main__':
# 创建互斥锁,赋值(串行)
mutex = Lock()
# 循环10次 模拟抢票
for i in range(1, 11):
# 创建子进程
p = Process(target=run, args=('用户%s' % i,mutex))
# 执行子进程
p.start()
8.总结(抢票系统)解析
acquire和release方法之间的代码同一时刻只能有一个线程去操作
如果在调用acquire方法的时候 其他线程已经使用了这个互斥锁,那么此时acquire方法会堵塞,直到这个互斥锁释放后才能再次上锁。
提示:加上互斥锁,那个线程抢到这个锁我们决定不了,那线程抢到锁那个线程先执行,没有抢到的线程需要等待
六:IPC机制(进程间通信)--队列
1.队列概况
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)
2.Queue概念介绍
创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
底层队列使用管道和锁定实现。
3.注意
- 队列:先进先出
- 队列的数据放进去,取走就没了
4.(消息队列)代码搭建
1.full和get_nowait不能用于多进程情况下的精确使用
2.队列的使用就可以打破进程间默认无法通信的情况
- 队列:先进先出
from multiprocessing import Queue
# 创建队列 不写默认2147483647
q = Queue(5) # 括号内可以填写最大等待数
# 存放数据
q.put(111)
q.put(222)
# print(q.full()) # False 判断队列中数据是否满了
q.put(333)
q.put(444)
q.put(555)
# print(q.full()) # True
# q.put(666) # 超出范围原地等待 直到有空缺位置
# 提取数据
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# print(q.get()) # 没有数据之后原地等待直到有数据为止
print(q.get_nowait()) # 没有数据立刻报错
七:(IPC消息队列)实现进程通信代码
1.主进程与子进程通信
进程间通信
相当于主进程与子进程通信 直白说是 存取数据
- 主进程与子进程代码实现通信
from multiprocessing import Queue, Process
def consumer(q):
# 提取数据
print(q.get())
# 存放数据
q.put('子进程存放的数据')
if __name__ == '__main__':
# 创建队列 赋值 默认不写 无限长
q = Queue()
# 存放数据
q.put('主进程放的数据')
# 创建子进程
p = Process(target=consumer, args=(q,))
# 执行子进程
p.start()
# 主进程等子进程执行完 再执行子进程
p.join()
# 提取数据
print(q.get())
print('主')
2.子进程与子进程通信
子进程与子进程之间通信
- 子进程与子进程之间通信代码实现
from multiprocessing import Queue, Process
def producer(q):
# 存放数据
q.put("子进程p放的数据")
def consumer(q):
# 数据 提取数据
print('子进程c取的数据', q.get())
if __name__ == '__main__':
# 创建 队列 赋值
q = Queue()
# 创建两个子进程
p = Process(target=producer, args=(q,))
c = Process(target=consumer, args=(q,))
# 执行子进程
p.start()
# 执行子进程
c.start()
八:生产者消费者模型
- JoinableQueue队列实现生产者消费者模型
生产者消费者模型需要用到JoinableQueue模块 跟queue功能一样,但更加完善
- JoinableQueue 这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
1.参数介绍
- maxsize是队列中允许最大项数,省略则无大小限制。
2.方法介绍
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止,也就是队列中的数据全部被get拿走了。
守护进程会随着主进程的结束而结束
3.场景规划
- 1.生产者
负责产生数据(做包子的) - 2.消费者
负责处理数据(吃包子的) - 该模型需要解决并发不平衡现象
4.生产者消费者模型(搭建)
from multiprocessing import Queue, Process, JoinableQueue
import time
import random
def producer(name, food, q):
for i in range(10):
print('%s 生产了 %s' % (name, food))
q.put(food)
# 制造延迟(随机)
time.sleep(random.random())
# 消费者
def consumer(name, q):
# 开启则循环
while True:
# 等待 数据 并获取
data = q.get()
print('%s 吃了 %s' % (name, data))
q.task_done() # 使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。
if __name__ == '__main__':
# q = Queue()
q = JoinableQueue()
# 生产者
p1 = Process(target=producer, args=('大厨jason', '玛莎拉', q))
p2 = Process(target=producer, args=('印度阿三', '飞饼', q))
p3 = Process(target=producer, args=('泰国阿人', '榴莲', q))
c1 = Process(target=consumer, args=('阿飞', q))
p1.start()
p2.start()
p3.start()
# 设置为守护进程(一定要放在start语句上方)
c1.daemon = True
c1.start()
# 调整所有进程的优先级优于主进程, 这样就能保证主进程最后执行完毕, 确保生产者进程全都结束了
# 我要确保你的生产者进程结束了,生产者进程的结束标志着你生产的所有的人任务都已经被处理完了
p1.join()
p2.join()
p3.join()
# 生产完毕,使用此方法进行阻塞,直到队列中所有项目均被处理。
q.join() # 等待队列中所有的数据被取干净
print('主')
5.总结(生产者消费模型)
- 1.等待逻辑顺序:主进程等--->p1,p2,p3等---->c1
- 2.p1,p2,p3结束了,证明c1肯定全都收完了p1,p2,p3发到队列的数据
- 3.因而c1也没有存在的价值了,不需要继续阻塞在进程中影响主进程了。应该随着主进程的结束而结束,所以设置成守护进程就可以了
进程(守护进程--互斥锁--IPC机制--生产者模型--僵尸进程与孤儿进程--模拟抢票--消息队列)的更多相关文章
- 守护模式,互斥锁,IPC通讯,生产者消费者模型
'''1,什么是生产者消费者模型 生产者:比喻的是程序中负责产生数据的任务 消费者:比喻的是程序中负责处理数据的任务 生产者->共享的介质(队列)<-消费者 2,为何用 实现了生产者与消费 ...
- 守护、互斥锁、IPC和生产者消费者模型
守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are ...
- 4月25日 python学习总结 互斥锁 IPC通信 和 生产者消费者模型
一.守护进程 import random import time from multiprocessing import Process def task(): print('name: egon') ...
- Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型
Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型 一丶互斥锁 含义: 每个对象都对应于一个可称为" 互斥锁&qu ...
- 并发编程 - 进程 - 1.互斥锁/2.模拟抢票/3.互斥锁与join区别
1.互斥锁: 互斥锁:Lock 原理就是把并发变成串行,一个一个运行,不错乱,但效率低 保证多个进程修改一块数据时,大家是一个一个修改,不错乱 mutex.acquire() mutex.releas ...
- 守护进程,互斥锁,IPC,队列,生产者与消费者模型
小知识点:在子进程中不能使用input输入! 一.守护进程 守护进程表示一个进程b 守护另一个进程a 当被守护的进程结束后,那么守护进程b也跟着结束了 应用场景:之所以开子进程,是为了帮助主进程完成某 ...
- 网络编程基础----并发编程 ---守护进程----同步锁 lock-----IPC机制----生产者消费者模型
1 守护进程: 主进程 创建 守护进程 辅助主进程的运行 设置进程的 daemon属性 p1.daemon=True 1 守护进程会在主进程代码执行结束后就终止: 2 守护进程内无法再开启子进程 ...
- 守护进程,互斥锁, IPC ,Queue队列,生产消费着模型
1.守护进程 什么是守护进程? 进程是一个正在运行的程序 守护进程也是一个普通进程,意思是一个进程可以守护另一个进程,比如如果b是a的守护进程,a是被守护的进程,如果a进程结束,b进程也会随之结束. ...
- Python 35 进程间的通信(IPC机制)、生产者消费者模型
一:进程间的通信(IPC):先进先出 管道:队列=管道+锁 from multiprocessing import Queue q=Queue(4) q.put(['first',],block=T ...
随机推荐
- Git统计代码变化率
统计2017-03-01到2017-03-31代码变更率 代码统计命令参考:git log --pretty=tformat: --since ==2017-03-01 --until=2017-03 ...
- Windows10 c++获取网卡信息(ipv4,子网掩码,网关,mac地址)
关于 本文样式环境: win10 + vs2017 + c++11 1.说明 算是踩坑吧,先前一直认为一块网卡只能有一个IP. 今天发现结构体中,定义了相关结构: 一块网卡可以用多个IP. 2.连接库 ...
- 【LeetCode】760. Find Anagram Mappings 解题报告
[LeetCode]760. Find Anagram Mappings 解题报告 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/find ...
- 【LeetCode】93. Restore IP Addresses 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 回溯法 日期 题目地址:https://leetco ...
- 1079 - Just another Robbery
1079 - Just another Robbery PDF (English) Statistics Forum Time Limit: 4 second(s) Memory Limit: 3 ...
- hdu 4503 湫湫系列故事——植树节(组合概率)
这是一道求组合的题.中文题面应该能看懂,废话不多说下面来说说这道题. 可以选的总组合数是Ck3 那么选到3个人的关系都相同,要么都认识,要么都不认识.可以重反面来考虑,就是求三个人的关系不都相同. 那 ...
- 【剑指Offer】二叉搜索树的第k个结点 解题报告(Python)
[剑指Offer]二叉搜索树的第k个结点 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-intervie ...
- 1127 - Funny Knapsack
1127 - Funny Knapsack PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB ...
- CH7511|LT7211|PS8625替代方案 CS5211 设计EDP转LVDS优势方案原理图+PCB板设计
CH7511|LT7211|PS8625这三款都是专门用于设计EDP转LVDS转接板或者屏转换方案板,CH7511.LT7211.PS8625目前这几款都是出于缺货状态,台湾瑞奇达Capstone 新 ...
- 网络划分和各层协议以及webservice 浅谈
最近在公司做一些和其他外部系统接口调用的工作,遇到一些网络传输的问题,趁周末的时间记录.整理一下. 提到网络我们不得不提网络的分层架构: 我们通常听到 网络七层架构/五层架构/四层架构,但是不了解很容 ...