Python守护进程、进程互斥锁、进程间通信ICP(Queue队列)、生产者消费者模型

  • 守护进程

    守护进程
    守护进程:p1.daemon=True
    守护进程其实就是一个“子进程“,守护=》伴随
    守护进程会伴随主进程的代码运行完毕后而死掉
    进程:当父进程需要将一个任务并发出去执行,需要将该任务放到以个子进程里
    守护:当该子进程内的代码在父进程代码运行完毕后就没有存在的意义了,就应该
    将该子进程设置为守护进程,会在父进程代码结束后死掉

from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == '__main__':
    p1=Process(target=foo)
    p2=Process(target=bar)

    # 将子进程p1设置为守护进程,
    # 所以p1会在print("main-------")打印完成后死掉,所以p1进程不会打印
    p1.daemon=True
    p1.start()
    p2.start()
    # time.sleep(1)
    print("main-------")

主进程代码运行完,但是主进程不会死,还要回收子进程的僵尸进程,
所有守护进程只是守护主进程代码运行完就会死掉

p.daemon=True #守护进程要放在进程start之前
p.start()
print(‘主’)

(1):正常情况子进程p不会打印,而会直接打印‘主’
(2):个别请况电脑速度快的时候,子类p里面的代码可能会运行(可能不是全部),然后等
主进程打印输出后,p会死掉(代码自上而下运行,操作系统产生并造出子类的速度快的前提下)

  • 进程间互斥锁

    互斥锁:就是将要执行任务的部门代码(只涉及到修改共享数据的代码)变成串行

    第一步:导入multiprocessing方法下面的Lock类
    第二步:在if name == ‘main’:方法下面调用Lock类mutex=Lock(),拿到一个对象
    第三步:在子类中需要共享的数据前后加入 加锁:mutex.acquire()——》需要共享修改数据的代码体《解锁:——mutex.release()

    实验:实现简单的抢票功能
    分析:1)查看变为并发(实现大家查询到的车票信息是一致的)
    2)购买变为串行(因为购买涉及到了修改数据信息,所以一定要遵循先到先得)

    (理解为用锁来限制,同一时间只能让一个人拿着锁去改数据,先抢到锁的人
    就有优先购买的权限)

    join:是将子类里面的所有代码都整体串行(就会将查询、购买2部分全部都变为串行,延迟更高)
    互斥锁:可以挑选一段代码(修改数据即买票的那部分)单独抽出来加锁

#模拟抢票软件的原理:
from multiprocessing import Lock,Process
import json,os,time,random

def check():               #查票功能实现并行访问
    time.sleep(1)
    with open('db.txt','rt',encoding='utf-8') as f:
        dic=json.load(f)
        print('%s 查看余票数为 %s'%(os.getpid(),dic['count']))

def get():               #购票因为牵涉到对后台数据的修改,所以加互斥锁目的是逐一进行访问修改,以免数据错乱
    with open('db.txt', 'rt',encoding='utf-8') as f:
        dic = json.load(f)
    time.sleep(2)
    if dic['count'] >0:
        #有票
        dic['count']-=1
        time.sleep(random.randint(1, 3))          #在购票时,模拟网络延迟...
        with open('db.txt', 'wt',encoding='utf-8') as f:
            json.dump(dic,f)
        print('%s 购票成功'%os.getpid())
    else:
        print('%s 没有余票'%os.getpid())

def task(mutex):
    #查看(并行访问)
    check()
    #抢票(加入互斥锁,实现串行访问,先到先得原则)
    mutex.acquire()
    get()
    mutex.release() #第一个购买完成后,解锁,后续进入继续购买


if __name__ == '__main__':
     mutex=Lock()   #调用Lock类拿到一个对象
     for i in range(10):
         p=Process(target=task,args=(mutex,))
         p.start()
  • 进程间的通信

    需求的演变思路:就是为了用一块儿共享的内存==》实现进程间的共享
    必须有2个特点:
    1.一定是内存空间
    2.能够自动帮忙处理锁的问题

    IPC机制:
    PIPE:管道
    Queue:PIPE+锁(队列)

    注意:
    1.队列占用的是内存空间
    2.不应该往队列中放大数据,应该只存放数据量较小的精简的内容

# 同样也是在multiprocessing方法里面导入Queue模块:

from multiprocessing  import Queue
# q.put()括号里面可以传多种数据类型
#定义队列里面存在数据的个数,先进先出原则

# 1.block、time是搭配使用的
# 2.False:一般单独使用,会立即报错(打印提示信息)

q=Queue(3)

# #存数据
# q.put('first')
q.put({'k':'second'})
q.put(['two',])
q.put(['three',])
# q.put(4,block=True,timeout=3) #*****如果不加block=True,timeout=3备注,一直是收取的状态
# #block=True timeout:意思是管道满了无法再往里面放,并且会等待3秒
# 如果还是满的状态,就会报错(如果不加程序是一直加载状态不会报错)

print(q.get())
print(q.get())
print(q.get())
# print(q.get(block=True,timeout=2)) #***如果不跟参数,会打印前3个,后卡在那里..
#block=True,timeout=2,加了如果管道里面没有数据,等待2秒后会报错(提示信息)

#注意无论是收还是发:当block=False的时候,是会直接报错,(所以False一般不与time搭配使用)
# print(q.get(block=False)

  • 生产消费者模型

    1.为什么是生产者消费者模型
    生产者:比喻的是程序中负责产生数据的任务
    消费者:比喻的是程序中负责处理数据的任务

    生产者———>共享的介质(队列)<————消费者

    2.为何用
    实现生产者与消费者的解耦和,生产者可以不停的生产,消费者也可以不停的消费
    从而平衡了生产者的生产能力与消费者消费能力,提升了而整体运行的效率

    什么时候用:
    当我们程序中存在明显的两类任务,一类是负责产生数据,一类是负责处理数据,此时
    就应该考虑使用生产者消费者模型来提升程序的效率

#消费者给生产者发信号,...等队列结束JoinableQueue,对队列被取空了
from multiprocessing import Queue,Process,JoinableQueue

import time
import os
import random

def producer(name,food,q):
    for i in range(2):
        res='第%s食物%s'%(i,food)
        time.sleep(random.randint(1,3))
        q.put(res)    #往管道传数据
        print('\033[45m%s 生产了 %s\033[0m'%(name,res))

def consumer(name,q):
    while True:
        time.sleep(random.randint(1, 3))
        res=q.get()   #从管道取数据
        if res is None:break
        print('%s 吃了 %s'%(name,res))
        q.task_done()   #最终版新增,执行完一次get 就告诉系统有一个数据被取走了


if __name__ == '__main__':
    # q=Queue()
    q=JoinableQueue()  #
    p1=Process(target=producer,args=('生产1','包子',q,))
    p2=Process(target=producer,args=('生产2','面条',q,))
    p3=Process(target=producer,args=('生产3','米饭',q,))


    c1=Process(target=consumer,args=('消费1',q,))
    c2=Process(target=consumer,args=('消费2',q,))

    c1.daemon=True  #开始前将子进程设置为守护进程
    c2.daemon=True

    #开始造食物
    p1.start()
    p2.start()
    p3.start()
    #开始造消费者

    c1.start()
    c2.start()

    #保证食物完全造好到管道里面
    # p1.join()   #保证全部生产完,放入管道
    # p1.join()
    # p1.join()
    # q.put(None)
    # q.put(None)

    #等所有生产者都生产完了,再执行
    p1.join()
    p2.join()
    p3.join()
    #这样就保证一定是队列里面就不会有新东西再放了...
    q.join()   #等待队列被取干净,执行的同时统计队列里面有多少个值,碰到一个q.task_done()就减1
    # 主进程的代码运行完毕--->(生产者运行完毕)+队列中的数据也被取干净了->消费者没有存在的意义

    #等到队列取空就执行下一行代码
    # print('主程序')

    #消费者没结束:
    #生产者已经结束了,此时就是消费者也已经取完了数据,那么就用到了守护进程
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值