第一阶段:Python开发基础 day37 进程的锁和队列以及生产消费模型

一,上节课内容回顾

'''
多道技术:
空间复用:多个程序公用一个内存条,彼此隔离,物理级别隔离
时间复用:公用一个cpu

切换的情况:
    io切,占用时间过长也切

串行:一个任务完完整整的运行结束,再运行下一个任务.
并发:看起来是同时执行多个任务     单核
并行:真正的做到了同时执行多个任务 多核



'''
###### 方式一
# from multiprocessing import Process
#
#
# def task():
#     pass
#
#
# if __name__ == '__main__':
#     p = Process(target=task)
#     p.start()
###### 方式二

# from multiprocessing import Process
#
# class MyP(Process):
#     def run(self):
#         pass
#
# if __name__ == '__main__':
#     p = MyP()
#     p.start() # 给操作系统发一个亲请求,操作系统去开进程
#     print('sadf')
#

###### 申请一个空间,把父进程的代码完整的copy一份放进去,然后去运行代码.


###### join回顾
# from multiprocessing import Process
# import time,os
#
# def task(s):
#     time.sleep(s)
#
#
# if __name__ == '__main__':
#
#     p1 = Process(target=task,args=(100,))
#     # p2 = Process(target=task,args=(2,))
#     # p3 = Process(target=task,args=(3,))
#
#     p1.start()
#     # p2.start()
#     # p3.start()
#     # p1.join() # 等1s,
#     # p2.join() # 等1s,
#     # p3.join() # 等1s,内部会调用wait()
#     # print(p1.pid)
#     print('子',p1.pid)
#     print('主',os.getpid()) # 主进程要等待所有的子进程结束才会结束.因为主进程要在结束前回收僵尸进程.(*****)

###### 僵尸进程. 没有死透的子进程.
     # 孤儿进程,子进程运行的过程父进程死了就变成了孤儿进程,被进程init接管.

# 父进程一直不死,一直在开启子进程,意味着占用过过多的pid并且不回收.
# 解决方案: 强制杀死这个父进程.


##### 守护进程
# 本质也是个进程
# 主进程的代码执行完毕守护进程直接结束。
# 大前提: 主进程结束之前守护进程一直运行着.
# from multiprocessing import Process
# import time
# def task():
#     print('守护进程  start')
#     # time.sleep(4)
#     print('守护进程  end')
#
#
# if __name__ == '__main__':
#     p = Process(target=task)
#     p.daemon = True
#     p.start()
#     time.sleep(2)
#     print('主')


# 进程锁 (***)
#  进程锁 是把锁住的代码变成了串行

# 队列(*****)
#  主要掌握put 和 get

# 生产者消费者模型(*****)
# 自己敲一遍 重点掌握这种思想

#JoinableQueue(*)
# 看一下里面的守护进程.

# 初识线程(好好理解一下) (*****)

二、优化抢票

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

def search():
    time.sleep(1) # 模拟网络io
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        print(f'还剩{res["count"]}')

def get():
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        # print(f'还剩{res["count"]}')
    time.sleep(1) # 模拟网络io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt',mode='wt',encoding='utf-8') as f:
            json.dump(res,f)
            print(f'进程{os.getpid()} 抢票成功')
        time.sleep(1.5) # 模拟网络io
    else:
        print('票已经售空啦!!!!!!!!!!!')

def task(lock):
    search()

    # 锁住
    lock.acquire()
    get()
    lock.release()
    # 释放锁头

if __name__ == '__main__':
    lock = Lock() # 写在主进程是为了让子进程拿到同一把锁.
    for i in range(15):
        p = Process(target=task,args=(lock,))
        p.start()
        # p.join()

    #  进程锁 是把锁住的代码变成了串行
    #  join 是把所有的子进程变成了串行


# 为了保证数据的安全,串行牺牲掉效率.

二、队列

# ipc机制 进程通讯
# 管道:pipe 基于共享的内存空间
# 队列:pipe+锁 queue
from multiprocessing import Process,Queue

### 案例一
# q = Queue()
# q.put('鲁照山')
# q.put([1,2,4])
# q.put(2)
# print(q.get())
# print(q.get())
# print(q.get())
# # q.put(5)
# # q.put(5)
# print(q.get()) # 默认就会一直等着拿值



### 案例2
# q = Queue(4)
# q.put('鲁照山')
# q.put([1,2,4])
# q.put([1,2,4])
# q.put(2)
#
# q.put('乔碧萝')  #队列满了的情况再放值,会阻塞


### 案例3 (从这往下都是了解)
# q = Queue(3)
# q.put('zhao',block=True,timeout=2) #
# q.put('zhao',block=True,timeout=2) #
# q.put('zhao',block=True,timeout=2) #
#
# q.put('zhao',block=True,timeout=5) # put里的  block=True 如果满了会等待,timeout最多等待n s,如果ns还是队列还是满的就报错了

### 案例4
# q = Queue()
# q.put('yyyy')
# q.get()
# q.get(block=True,timeout=5) # block=True 阻塞等待,timeout最多等5s, 剩下同上

### 案例5

# q = Queue(3)
# q.put('qwe')
# q.put('qwe')
# q.put('qwe')
#
# q.put('qwe',block=False) # 对于put来说block=False 如果队列满了就直接报错

# q = Queue(3)
# q.put('qwe')
# q.get()
#
#
# q.get(block=False)
# block = Flase 拿不到不阻塞,直接报错

### 案例6
q = Queue(1)
q.put('123')
# q.get()
q.put_nowait('666') # block = False
# q.get_nowait() # block = False
#

三、生产者消费者模型

'''
生产者: 生产数据的任务
消费者: 处理数据的任务

生产者--队列(盆)-->消费者

生产者可以不停的生产,达到了自己最大的生产效率,消费者可以不停的消费,也达到了自己最大的消费效率.
生产者消费者模型大大提高了生产者生产的效率和消费者消费的效率.


# 补充: queue不适合传大文件,通产传一些消息.
'''

from multiprocessing import Process,Queue

def producer(q,name,food):
    '''生产者'''
    for i in range(10):
        print(f'{name}生产了{food}{i}')
        res = f'{food}{i}'
        q.put(res)
    q.put(None)

def consumer(q,name):
    '''消费者'''
    while True:
        res = q.get(timeout=5)
        if res is None:break
        print(f'{name}吃了{res}')

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer,args=(q,'rocky','包子'))
    c1 = Process(target=consumer,args=(q,'成哥'))
    p1.start()
    c1.start()

四、测试join ablequeue

from multiprocessing import Process,Queue,JoinableQueue


q = JoinableQueue()

q.put('zhao') # 放队列里一个任务
q.put('qian')

print(q.get())
q.task_done() # 完成了一次任务
print(q.get())
q.task_done() # 完成了一次任务
q.join() #计数器不为0的时候 阻塞等待计数器为0后通过

# 想象成一个计数器 :put +1   task_done -1

五、初步识别线程

'''
初识别线程.
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程
在工厂中,  每个车间都有房子,而且每个车间默认就有一条流水线.

操作系统 ===> 工厂
进程 ===> 车间
线程 ===> 流水线
cpu  ===> 电源

线程:cpu最小的执行单位
进程:资源集合/资源单位.
线程运行 = 运行代码
进程运行 = 各种资源 + 线程

'''
posted @ 2019-09-17 17:12  foreversun92  阅读(174)  评论(0编辑  收藏  举报