day33 守护进程、互斥锁、进程间通信、生产者消费者模型part1、生产者消费者模型part2、生产者消费者模型part3

1、守护进程

  守护进程其实就是一个'子进程'

  守护=>伴随

  守护进程会伴随主进程的代码运行完毕后而死掉

2、为何用守护进程

  关键字就两个"

    进程:

      当父进程需要将一个任务并发出去执行,需要将该任务放到一个子进程里

    守护:

      当该子进程内的代码在父进程代码运行完毕后就没有存在的意义了,就应该将该

    子进程设置为守护进程,会在父进程代码结束后死掉。

from multiprocessing import Process
import time,os

def task():
    print('%is running'%os.getpid())  #获得的事进程的pid   ppid查看其父进程的id号
    time.sleep(3)

if __name__=='__main__':
    p=Process(target=task)
    p.daemon=True#一定要放到p.start()之前  p.daemon为其守护进程
    p.start()
    print('主')
    print('%主is running' % os.getpid())
#如何把一个子进程做成守护进程呢?

#到底是什么场景需要子进程?
#生产者消费者模型的时候

互斥锁

错误1:一张票卖了10次  (购票操作不应该并发,而是应该串行)

from multiprocessing import Process
import json
import os
import time
import random

def check():
    time.sleep(random.randint(1,3))#1~3  模拟网络延迟
    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(random.randint(1,3))
    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():
    #查票
    check()
    #购票
    get()

if __name__ == '__main__':
    for i in range(10):
        p=Process(target=task)
        p.start()

#db.txt文件
{"count": 0}

错误2:查票应该是并发的 购票应该是串行的,保证数据安全的核心是并发编程串行

from multiprocessing import Process
import json
import os
import time
import random

def check():
    time.sleep(random.randint(1,3))#1~3  模拟网络延迟
    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(random.randint(1,3))
    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():
    #查票
    check()
    #购票
    get()

if __name__ == '__main__':
    for i in range(10):
        p=Process(target=task)
        p.start()
        p.join()

#db.txt文件
{"count": 0}

正确的方法:加互斥锁:

from multiprocessing import Process,Lock
import json
import os
import time
import random

def check():
    time.sleep(random.randint(1,3))#1~3  模拟网络延迟
    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(random.randint(1,3))
    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()#互斥锁不能连续的acquire,必须是release后才能重新acquire
    get()
    mutex.release()
    # with mutex:#简写版
    #     get()
if __name__ == '__main__':
    mutex=Lock()
    for i in range(10):
        p=Process(target=task,args=(mutex,))
        p.start()
#db.txt文件
# {"count": 0}


#互斥锁:将并发变成串行,牺牲了效率保证了数据安全

 互斥锁跟之前的join思路一样,都是将并发编程串行。join是真正意义上的穿行 join所有的都串行,join是查票都变成串行了,所以join将要执行的代码编程整体的串行。

互斥锁:可以将部分代码(只涉及到修改共享数据的代码)变成串行

join是将执行任务的所有代码整体串行

进程间通信

# IPC:进程间通信,有两种实现方式  #inter progress communicate 进程之间交流
# 1、pipe: #基于管道的
# 2、queue:pipe+锁 #基于队列的  队列是管道加锁实现的  管道和队列都是为了实现进程之间通信的

from multiprocessing import Queue
q=Queue(3) #先进先出
#注意:
#1、队列占用的是内存空间
#2、不应该往队列中放大数据,应该只存放数据量较小的消息
# 掌握的
q.put('first')
q.put({'k':'sencond'})
q.put(['third',])
q.put(4)

print(q.get())
print(q.get())
print(q.get())
print(q.get())

 

之前借助进程之间通信靠文件,文件是硬盘空间

硬盘的效率太低

需要另外一种介质来打破内存间介质的通信

需要一个共享的内存空间

在linux系统中 free -m查看共享的内存

进程间的通信应该用内存空间而不是硬盘空间

生产者消费者模型

生产者消费者模型
该模型中包含两类重要的角色:
1、生产者:将负责造数据的任务比喻为生产者
2、消费者:接收生产者造出的数据来做进一步的处理,该类人物被比喻成消费者


实现生产者消费者模型三要素
1、生产者
2、消费者
3、队列

什么时候用该模型:
程序中出现明显的两类任何,一类任务是负责生产,另外一类任务是负责处理生产的数据的

该模型的好处:
1、实现了生产者与消费者解耦和
2、平衡了生产力与消费力,即生产者可以一直不停地生产,消费者可以不停地处理,因为二者
不再直接沟通的,而是跟队列沟通

import time
import random
from multiprocessing import Process,Queue

def consumer(name,q):
    while True:
        res=q.get()
        time.sleep(random.randint(1,3))
        print('33[46m消费者===》%s 吃了 %s33[0m' %(name,res))


def producer(name,q,food):
    for i in range(5):
        time.sleep(random.randint(1,2))
        res='%s%s' %(food,i)
        q.put(res)
        print('33[45m生产者者===》%s 生产了 %s33[0m' %(name,res))


if __name__ == '__main__':
    #1、共享的盆
    q=Queue()

    #2、生产者们
    p1=Process(target=producer,args=('egon',q,'包子'))
    p2=Process(target=producer,args=('刘清政',q,'泔水'))
    p3=Process(target=producer,args=('杨军',q,'米饭'))

    #3、消费者们
    c1=Process(target=consumer,args=('alex',q))
    c2=Process(target=consumer,args=('梁书东',q))


    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()
#用爬虫比较好  二期视频补充了很多相关的知识

  

原文地址:https://www.cnblogs.com/wangmiaolu/p/9302951.html