一、守护进程

守护进程:一个进程B守护另一个进程A,当被守护的进程A结束,进程B也就结束了。(不一定同生,但会同死)

两个特点:

①守护进程会在主进程代码执行结束后就终止

②守护进程内无法再开启子进程,否则抛出异常。

注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

应用场景:如果主进程认为一旦自己结束,子进程也就没有继续运行的必要了,就可以将子进程设置为守护进程。(例如:qq正在调用自身的下载文件功能,但是此时退出了qq,下载进程也就可以直接关闭了)

方法为:process.daemon=True,必须放置在子进程开启前。

from multiprocessing import Process
import time
​
def task(name):
   print('%s is running' % name)
   time.sleep(3)
   print('%s is running' % name)  # 等待三秒的时候,被守护进程已经执行完了,所以守护进程会被回收,此句话就不会打印了。
​
​
if __name__ == '__main__':
   obj = Process(target=task, args=('守护进程',))
   obj.daemon=True  # 必须在start前设置,会限制p创建子进程,且父进程结束子进程马上殉葬结束。
   obj.start()  # 发送信号给操作系统
   time.sleep(1)
   print('被守护进程')
输出结果:
守护进程 is running
被守护进程
二、互斥锁

互斥锁:将并发变为串行(即一个一个运行)

from multiprocessing import Process,Lock
import time,random
​
mutex=Lock()  # 实例化互斥锁,也可以放到main下面。
# 强调:必须是lock.acquire()一次,然后 lock.release()释放一次,才能继续lock.acquire(),不能连续的lock.acquire(),否则会形成阻塞,程序卡死。
​
def task1(lock):
   lock.acquire() # 得到这把锁,此时其他的同级子进程都只能等待当前进程将锁释放之后才有机会运行。
   print('task1:名字是egon')
   time.sleep(random.randint(1,3))
   print('task1:性别是male')
   time.sleep(random.randint(1,3))
   print('task1:年龄是18')
   lock.release()  # 锁用完之后,一定要释放,否则其他子进程无法进行
​
def task2(lock):
   lock.acquire()  # 是一个阻塞的函数 会等到别的进程释放锁才能继续执行
   print('task2:名字是alex')
   time.sleep(random.randint(1,3))
   print('task2:性别是male')
   time.sleep(random.randint(1,3))
   print('task2:年龄是78')
   lock.release()
​
​
def task3(lock):
   lock.acquire()
   print('task3:名字是lxx')
   time.sleep(random.randint(1,3))
   print('task3:性别是female')
   time.sleep(random.randint(1,3))
   print('task3:年龄是30')
   lock.release()
​
​
if __name__ == '__main__':
   p1=Process(target=task1,args=(mutex,))  # 创建进程并传参,将锁传给各个子进程
   p2=Process(target=task2,args=(mutex,))
   p3=Process(target=task3,args=(mutex,))
   p1.start()   # 三个子程序都能启动,但是一旦碰到锁,谁先抢到谁先运行,其他的要等。
   p2.start()
   p3.start()

互斥锁与join的区别:

二者原理都一样,都是将并发变为串行,从而保证数据增删改查的有序性,不至于让数据发生错乱。

二者的区别在于join是按照人为指定顺序执行,进程执行顺序是固定的,而互斥锁是所有进程公平竞争,谁先抢到锁,谁就能先执行;且互斥锁可以指定某一部分代码串行,其余部分代码并发,而join则是整个子进程代码完全串行。

互斥锁的本质是一个布尔类型的数据,在执行代码前,会先判断这个值。

互斥锁在抢票中的应用:

import json
from multiprocessing import Process,Lock
import time
import random
​
# 查看剩余票数
def check_ticket(usr):
   time.sleep(random.randint(1,3))
   with open("ticket.json","r",encoding="utf-8") as f:   # 提前做好json文件,做成字典。
       dic = json.load(f)
       print("%s查看 剩余票数:%s" % (usr,dic["count"]))
​
def buy_ticket(usr):
   with open("ticket.json","r",encoding="utf-8") as f:
       dic = json.load(f)
       if dic["count"] > 0:
           time.sleep(random.randint(1,3))
           dic["count"] -= 1
           with open("ticket.json", "w", encoding="utf-8") as f2:  #
               json.dump(dic,f2)
               print("%s 购票成功!" % usr)
        else:
           print("票被抢走了!%s购票失败" % usr)
​
​
def task(usr,lock):
   check_ticket(usr)  # 查票可以并发
   lock.acquire()  # 排票就要串行了
   buy_ticket(usr)
   lock.release() # 买好票后要释放锁
​
if __name__ == '__main__':
   lock = Lock()
   for i in range(10):   # 启动10个进程去买票,模仿10个人。
       p = Process(target=task,args=("用户%s" % i,lock))
       p.start()
       
输出结果:   #每次结果可能都不一致
用户0查看 剩余票数:1
用户2查看 剩余票数:1
用户3查看 剩余票数:1
用户1查看 剩余票数:1
用户0 购票成功!
票被抢走了!用户2购票失败
票被抢走了!用户3购票失败
票被抢走了!用户1购票失败
用户5查看 剩余票数:0
票被抢走了!用户5购票失败
用户4查看 剩余票数:0
票被抢走了!用户4购票失败
用户7查看 剩余票数:0
票被抢走了!用户7购票失败
用户6查看 剩余票数:0
票被抢走了!用户6购票失败
用户9查看 剩余票数:0
票被抢走了!用户9购票失败
用户8查看 剩余票数:0
票被抢走了!用户8购票失败

Rlock

RLock 表示可重入锁,其特点是可以多次执行acquire而不会阻塞。
如果在多进程中使用Rlock,并且一个进程a 执行了多次acquire,其他进程b要想获得这个锁,需要进程a把锁解开,并且锁了几次就要解几次。
普通锁如果多次执行acquire将会锁死(阻塞)
from multiprocessing import RLock,Process
import time
def task(i,lock):
   lock.acquire()
   lock.acquire()
   print(i)
   time.sleep(3)
   lock.release()
   lock.release()  #第一个过来 睡3秒 第二个过来了 睡3秒   第一个打印1 第二个打印2
​
if __name__ == '__main__':
   lock = RLock() # 重入锁,即多次锁
   p1 = Process(target=task,args=(1,lock))
   p1.start()
   p2 = Process(target=task,args=(2,lock))
   p2.start()

死锁:指锁无法打开,导致程序无法继续运行。即两把锁交给了两个人,这两个人还都需要对方的那把锁,互相谁也无法释放锁,也得不到对方的锁。

程序中尽可能不要使用多把锁,防止发生死锁现象

from multiprocessing import Process,Lock
import time
def task1(l1,l2,i):
   l1.acquire()  # 拿走了l1的锁,但是task2拿走了l2的锁,两个进程后续都无法进行。
   print("盘子被%s抢走了" % i)
   time.sleep(1)
   l2.acquire()
   print("筷子被%s抢走了" % i)
   print("吃饭..")
   l1.release()
   l2.release()
​
​
def task2(l1,l2,i):
   l2.acquire()
   print("筷子被%s抢走了" % i)
   l1.acquire()
   print("盘子被%s抢走了" % i)
   print("吃饭..")
   l1.release()
   l2.release()
​
​
if __name__ == '__main__':
   l1 = Lock()
   l2 = Lock()
   Process(target=task1,args=(l1,l2,1)).start()
   Process(target=task2,args=(l1,l2,2)).start()
三、IPC通信

IPC:进程间通信, 进程间相互独立,所以要解决进程间相互传输数据的问题。 1、使用共享文件,多个进程同时读写一个文件 ​ 受限IO,速度慢 2、管道,基于内存速度快,但是是单向的,比较麻烦 3、申请共享内存空间,进程们可以共享这片区域 ​ 基于内存速度快,但是数据量不能太大

from multiprocessing import Process,Manager,Lock  # 导入manager
import time
​
mutex=Lock()
​
def task(dic,lock):
   lock.acquire()  # 如果不加锁,都会读取字典,然后修改,结果就是变成9
   temp=dic['num']
   time.sleep(0.1)  # 读取共享空间之后,沉睡0.1秒,让所有进程都能运行起来
   dic['num']=temp-1
   lock.release()
​
if __name__ == '__main__':
   m=Manager()  # 实例化manager
   dic=m.dict({'num':10}) # 建立一个字典对象,这是子进程的共享空间
   l=[]
   for i in range(10):
       p=Process(target=task,args=(dic,mutex))
       l.append(p)
       p.start()
​
   for p in l:
       p.join()  # 子进程都结束后,再去查看字典
   print(dic)
输出结果:
{'num': 0}
如果不加锁,CPU和内存足够快,输出结果可能为{'num':9}
四、队列

一种数据容器,特点是先进先出。(栈是后进先出)

优点:是进程的共享空间,可以自动处理锁的问题(如上小节中如果锁处理不好,就会发生数据错乱)

即便在多进程下,也可以保证数据不会错乱,因为put和get默认阻塞。

注意点:

1、队列用来处理进程间的数据,且在内存中,所以数据量不应过大;

2、限制maxsize的值如果超过了内存就变得毫无意义。

from multiprocessing import Queue
​
q = Queue(1)  # 实例化一个队列,最多可以存一个数据
q.put("张三")  # 将数据放进队列中
print(q.get())  # 将数据从队列中拿出
q.put("李四") # 当容器装满时,put默认会阻塞 。如果上一步中没有get,此时就会阻塞
q.put("福布斯",False) # False表示不会阻塞 无论容器是满了 都会强行塞 如果满了就抛异常
​
print(q.get())
print(q.get()) # 当容器中数据时,get默认阻塞
print(q.get(timeout=3)) # timeout 仅用于阻塞时,此处表示会等待3秒,三秒后如果还取不到数据,就会报错queue.Empty
​
print("over")  # 因为阻塞,此句不会打印
def put(self, obj, block=True, timeout=None):  # block表示阻塞,timeout表示等待时间。
   pass
​
def get(self, block=True, timeout=None):
   pass
五、生产者消费者模型

生产者:数据的生产者

消费者:处理数据者

生产者消费者模型三要素:生产者、消费者、队列

应用场景:程序中出现明显的两类,一类负责生产数据,另一类负责处理数据时。

该模型优点:

1、实现了数据生产者与数据消费者之间的解耦合

2、平衡了生产力和消费力,即生产者只关心生产即可,消费者只关心处理数据即可,二者通过队列沟通。

import random
from multiprocessing import Process,Queue
import time
# 爬数据
def get_data(q):
​
   for num in range(5):
       print("正在爬取第%s个数据" % num)
       time.sleep(random.randint(1,2))
       print("第%s个数据 爬取完成" % num)
       # 把数据装到队列中
       q.put("第%s个数据" % num)
​
​
def parse_data(q):  # 生产者只关心生产即可,队列数最大为5,如果队列满了就进入阻塞状态。
   for num in range(5):
       # 取出数据
       data = q.get()
       print("正在解析%s" % data)
       time.sleep(random.randint(1, 2))
       print("%s 解析完成" % data)
​
if __name__ == '__main__':
   # 共享数据容器
   q = Queue(5)
   #生产者进程
   produce =  Process(target=get_data,args=(q,))
   produce.start()
   #消费者进程
   customer = Process(target=parse_data,args=(q,))
   customer.start()

20181229(守护进程,互斥锁,IPC,生产者和消费者模型)的更多相关文章

  1. 守护进程,互斥锁,IPC,队列,生产者与消费者模型

    小知识点:在子进程中不能使用input输入! 一.守护进程 守护进程表示一个进程b 守护另一个进程a 当被守护的进程结束后,那么守护进程b也跟着结束了 应用场景:之所以开子进程,是为了帮助主进程完成某 ...

  2. python并发编程之守护进程、互斥锁以及生产者和消费者模型

    一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...

  3. 进程(守护进程--互斥锁--IPC机制--生产者模型--僵尸进程与孤儿进程--模拟抢票--消息队列)

    目录 一:进程理论知识 1.理论知识 二:什么是进程? 三:僵尸进程与孤儿进程 1.僵尸进程 四:守护进程 1.什么是守护进程? 2.主进程创建守护进程 3.守护进程 五:互斥锁(模拟多人抢票) 1. ...

  4. 守护模式,互斥锁,IPC通讯,生产者消费者模型

    '''1,什么是生产者消费者模型 生产者:比喻的是程序中负责产生数据的任务 消费者:比喻的是程序中负责处理数据的任务 生产者->共享的介质(队列)<-消费者 2,为何用 实现了生产者与消费 ...

  5. 4 并发编程-(进程)-守护进程&互斥锁

    一.守护进程 主进程创建子进程,然后将该进程设置成守护自己的进程,守护进程就好比崇祯皇帝身边的老太监,崇祯皇帝已死老太监就跟着殉葬了. 关于守护进程需要强调两点: 其一:守护进程会在主进程代码执行结束 ...

  6. 8.9 day30 并发编程 进程理论 进程方法 守护进程 互斥锁

    多道技术 1.空间上的复用 多个程序共用一套计算机硬件 多道技术原理 2.时间上的复用 ​ 切换+保存状态 ​ 1.当一个程序遇到IO操作 操作系统会剥夺该程序的CPU执行权限( 提高了CPU的利用率 ...

  7. python并发编程-进程理论-进程方法-守护进程-互斥锁-01

    操作系统发展史(主要的几个阶段) 初始系统 1946年第一台计算机诞生,采用手工操作的方式(用穿孔卡片操作) 同一个房间同一时刻只能运行一个程序,效率极低(操作一两个小时,CPU一两秒可能就运算完了) ...

  8. 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发

    子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...

  9. (day29) 进程互斥锁 + 线程

    目录 进程互斥锁 队列和堆栈 进程间通信(IPC) 生产者和消费者模型 线程 什么是线程 为什么使用线程 怎么开启线程 线程对象的属性 线程互斥锁 进程互斥锁 进程间数据不共享,但是共享同一套文件系统 ...

  10. posix 匿名信号量与互斥锁 示例生产者--消费者问题

    一.posix 信号量 信号量的概念参见这里.前面也讲过system v 信号量,现在来说说posix 信号量. system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还 ...

随机推荐

  1. B/S模式获取客户端IP地址

    using System.Web; namespace Common { public class IPUtil { /// <summary> /// 获取IP地址 /// </s ...

  2. c#写word文档基础操作(自己控制样式)

    下面一个函数,建立一个Word 文档,添加页眉.页脚,在内容中两个不同字体的Hello!!!   来自 <http://bbs.csdn.net/topics/340041961> pub ...

  3. textArea 默认添加的空格

    1.会莫名多出一些空格(标签闭合换行了) <textarea class="borderstyle width97b height75" name="SmsTax. ...

  4. It does not do to dwell on dreams and forget to live.

    It does not do to dwell on dreams and forget to live.不要过于依赖梦想,却忘了生活.

  5. 【Shell脚本学习23】Shell函数参数

    在Shell中,调用函数时可以向其传递参数.在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数... 带参数的函数示例: #!/bin/bash funWit ...

  6. Nagios-4.1.1 (OpenLogic CentOS 7.2)

    平台: CentOS 类型: 虚拟机镜像 软件包: apache2.4.6 nagios 4.1.1 php5.4.16 devops monitoring nagios open-source ph ...

  7. docker使用alpine系统构建tomcat镜像

    FROM frolvlad/alpine-oraclejdk8 #此镜像使用alpine-glibc系统,精简jdk,只运行java程序,无法编译/构建 MAINTAINER huqiang:2018 ...

  8. v-if与v-show的区别

    一.区别 v-if 动态的向DOM树内添加或者删除DOM元素:“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建:在初始渲染条件为假时,什么也不做. v-sho ...

  9. 腾讯云服务器CVM购买详细过程 选择我们需要的腾讯云服务器

    腾讯云服务商有云服务器.云数据库.CDN.云存储等产品,其中较多的用户会选择腾讯云服务器,因为用途比较广泛,比如用来软件的运行以及网站建设,如今一般都是用云服务器,而不是用虚拟主机,毕竟虚拟主机的性价 ...

  10. draggable与overflow同时存在,无法拖拽出父元素问题解决

    在使用jquery-ui的拖拽功能对列表内的选项拖拽时,发现无法将选项拖拽出列表的范围,一出范围就自动隐藏在列表下,查找到最后的原因是css中的overflow的原因,overflow存在则不能将选项 ...