day 33 进程锁,进程之前互相通信,生产者消费者模型

进程锁 -multiprocess.Lock

锁的应用场景

对数据库的写操作必须是串行,读操作可以并行,没办法并发写的操作,如果并发对数据库写的操作会导致数据不一致性.

import time
import os
import json
from multiprocessing import Process,Lock
#用抢票系统来模拟一个进程锁
def search_piao(name):
    with open("ticket") as f: #with  open 打开一个文件默认的模式是读   ticket = {"count": 0}
        piao_dic = json.load(f)   #给字典赋予名字,利用名字操作字典
        time.sleep(0.1)
        print("%s查询了余票,还剩%s张" % (name,piao_dic["count"]))


def get_piao(n,lock):
    with open("ticket") as f:   #买票之前还需要再查询一遍还有几张票
        piao_dic = json.load(f)
    time.sleep(0.1)   #加上等待0.1秒是为了模仿生产环境中网络延迟,并行的机制会默认处理下一个用户,这样每个人查询的数据就不一致了
    if piao_dic["count"] > 0:   #先判断没有有票,如果有票就可以买
        print("%s查询了余票,还剩%s张" % (n,piao_dic["count"]))
        piao_dic["count"] -= 1
        print("%s购票成功,还剩下%s张票" % (n,piao_dic["count"]))
    time.sleep(0.1)
    with open("ticket",mode="w") as f:
        json.dump(piao_dic,f)


def buy_paio(name,lock):
    search_piao(name)
    lock.acquire()
    get_piao(name, lock)
    lock.release()

  #上下文关联写法

  def use_system(name,lock):
  search_ticket(name)
  with lock:
  buy_ticket(name)

if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        # p = Process(target=search_piao,args=("alex"+str(i),),name="搜索")
        # p.start()
        p1 = Process(target=buy_paio,args=("alex"+str(i),lock,),name="买票")
        p1.start()

 

进程队列-进程间通信(IPC(Inter-Process Communication))

认识进程队列:

    进程之间的数据安全

    对列最鲜明的特征就是先进先出  

    进程之间的数据本身是隔离的,但是用"Queue"方法可以做到多进程之间的互相通信

    队列底层: 是管道+锁实现的

        管道 ""Pipe"" 没有锁,数据是不安全的,""并发""效率高

 

Queue队列的集中方法:

          q = Queue()

          q.empty()     判断队列是否为空(由于网络延迟的原因,判断的都不准确,不建议使用)

          q.full()             判断队列是否为满(由于网络延迟的原因,判断的都不准确,不建议使用)

          q.qsize()        队列中数据的个数(由于网络延迟的原因,判断的都不准确,不建议使用)

          q.get_nowait()    拿取数据时超过队列池的限制数量的时候不会卡主,但是程序会抛出一个异常"queue.Empty".

          q.put_nowait()     存数据时超过队列池的限制数量的时候不会卡主,同样程序也会抛出一个异常"queue.Empty",生产环境不建议使用,一位这样会造成数据丢失.

子进程之间的互相同通信

def bar1(q):
    q.put("aaa")
    q.put("aaa") #超过数据池的限制,放第二条数据的时候会卡住

def bar2(q):
    print("-->",q.get())
    print("-->",q.get()) #超过数据池的限制,取第二条数据的时候同业也会卡住

if __name__ == '__main__':
    q = Queue(1)   #数据池,控制存放数据和拿取数据的数量
    p = Process(target=bar1,args=(q,))
    p.start()
    p2 = Process(target=bar2,args=(q,))
    p2.start()

#总结:当队列池限制存放数据数量时,往里面put或者get超过限制数量程序都会卡主
 

 

 

#子进程并发通信
import time
def bar(q):
    q.put("aaa")
    q.put("bbb")
    time.sleep(2)
    print("in bar get" ,q.get())

def bar2(q):
    print("in bar1 get",q.get())

if __name__ == '__main__':
    q = Queue()
    p = Process(target=bar,args=(q,))
    p.start()
    p1 = Process(target=bar2,args=(q,))
    p1.start()

#结果
in bar1 get aaa
in bar get bbb

 

生产者消费者模型

import time
import random
from multiprocessing import Process,Queue

def consumer(q,name):
    while True:   #消费者会循环接收生产这发出的数据
        begin_eat = q.get()
        if begin_eat == None : break
        time.sleep(random.random())   #0-1秒内吃一个蛋糕
        print("%s吃了%s" % (name,begin_eat))

def producer(q,n):
    for i in range(n):   #生产了10个蛋糕
        time.sleep(random.uniform(1,2))  #控制1-2秒生产一个蛋糕
        print("生产了蛋糕%s" % i)
        q.put("蛋糕%s" % i)



if __name__ == '__main__':
    q = Queue()
    lst = []
    for i in range(3):
        p = Process(target=producer,args=(q,10,)) #在主程序控制生产的数量
        p.start()
        lst.append(p)
    p2 = Process(target=consumer,args=(q,"alex"))
    p3 = Process(target=consumer,args=(q,"wusir"))  #这里用两个消费者是因为,单个消费者会消费的(吃)的太慢
    p2.start()
    p3.start()
    for i in lst:
        i.join()   #按照顺序拿出数据
    q.put(None)
    q.put(None)    #有几个消费者就要put几个"None"

 

posted @ 2019-02-27 16:31  jack_zhangn`  阅读(282)  评论(0编辑  收藏  举报