zoukankan      html  css  js  c++  java
  • 36 锁 信号量 事件

    课程回顾:
    并行 : 两个进程在同一时间点发生
    并发 : 两个进程在同一时间间隔内运行
    同步 : 某一个任务的执行必须依赖于另一个任务的返回结果
    异步 : 某一个任务的执行,不需要依赖于另一个任务的返回,只需要告诉另一个任务一声
    阻塞 : 程序因为类似于IO等待、等待事件等导致无法继续执行。
    非阻塞:程序遇到类似于IO操作时,不再阻塞等待,如果没有及时的处理IO,就报错或者跳过等其他操作

    进程的方法和属性:
    方法:start() 开启一个子进程
    join 异步变同步,让父进程等待子进程的执行结束,再继续执行
    is_alive, 判断进程是否活着
    terminate 杀死进程
    属性:
    name 子进程的名字
    pid 子进程的pid
    daemon 设置进程为守护进程,给一个True代表为守护进程,默认为False,不是守护进程
    守护进程
    特点:
    随着父进程的代码执行完毕才结束
    守护进程不能创建子进程
    守护进程必须要在start之前设置

    复习下代码
    主程序与子程序是异步的关系
    但是家上p.join()就同步了,主程序会等着子程序执行完
    from multiprocessing import Process
    import time
    
    
    
    def func():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.start()
        for i in range(10,21):
            print(i)
            time.sleep(1)
    ===============主程序、子程序交替打印
    10
    0
    1
    11
    2
    3
    12
    4
    5
    13
    6
    7
    14
    8
    9
    15
    16
    17
    18
    19
    20
    异步关系
    from multiprocessing import Process
    import time
    
    
    def func():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.start()
        p.join()     # 加上这行,就变成同步的了
        for i in range(10,21):
            print(i)
            time.sleep(1)    
    
    ==============先让子程序执行完、主程序才继续执行
    1-20
    同步关系

    守护进程 随着主进程结束而结束

    from multiprocessing import Process
    import time
    
    def func1():
        for i in range(65,90):
            print(chr(i))
            time.sleep(0.5)
    
    def func():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.start()
        p1 = Process(target=func1)
        p1.daemon = True
        p1.start()
    
    ===================
    0-9
    守护进程

    为什么上面的程序不打印func1()呢?

    因为主进程已经执行完了!所以func1做为主程序的守护进程来不及执行就结束了

    我们在主进程运行的时间多一点即可

    from multiprocessing import Process
    import time
    
    def func1():
        for i in range(65,90):
            print(chr(i))
            time.sleep(0.5)
    
    def func():
        for i in range(10):
            print(i)
            time.sleep(0.5)
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.start()
        p1 = Process(target=func1)
        p1.daemon = True
        p1.start()
        time.sleep(2)
    ======
    func1会打印2秒的值
    打印部分func1的值

    IPC -- inter process Communication 进程间通信


    提出问题:
    主进程和子进程的值共享吗?
    from multiprocessing import Process,Value,Lock
    import time
    
    def get_money(num):
        num -= 1
    
    def put_money():
        pass
    
    if __name__ == '__main__':
        num =100
        p = Process(target=get_money,args=(num,))
        p.start()
        p.join()
        print(num)
    
    
    # 100 不共享
    测试值共享吗?

    引入第三方模块Value

    from multiprocessing import Process,Value
    import time
    
    def get_money(num):      # 传入对象
        num.value -= 1
        print('子进程', num.value)
    
    def put_money():
        pass
    
    if __name__ == '__main__':
        num = Value('i',50)   # 实例化值,给一个数和类型
        p = Process(target=get_money,args=(num,))
        p.start()
        p.join()
        print(num.value)
    Value共享值

    value的不好的案例

    from multiprocessing import Process,Value,Lock
    import time
    
    def get_money(num):
        for i in range(100):
            num.value -= 1
            time.sleep(0.01)
    
    def put_money(num):
        for i in range(100):
            num.value +=1
            time.sleep(0.01)
    
    
    if __name__ == '__main__':
        num = Value('i',100)
        p1 = Process(target=get_money,args=(num,))
        p1.start()
        p2 = Process(target=put_money, args=(num,))
        p2.start()
        p1.join()
        p2.join()
        print(num.value)
    # 发现打印出来的值并不是100  而是在100左右摆动
    银行存取钱

    出现问题了,变量在赋值的时候混乱

    这时候,我们引入锁的机制

    from multiprocessing import Lock
    
    l = Lock()
    
    l.acquire()# 拿走钥匙,锁门,不让其他人进屋
    
    l.release()# 释放锁。  还钥匙,开门,允许其他人进屋
    from multiprocessing import Process,Value,Lock
    import time
    
    
    def get_money(num,l):# 取钱
        l.acquire()# 拿走钥匙,锁上门,不允许其他人进屋
        for i in range(100):
            num.value -= 1
            print(num.value)
            time.sleep(0.01)
        l.release()# 还钥匙,打开门,允许其他人进屋
    
    def put_money(num,l):# 存钱
        l.acquire()
        for i in range(100):
            num.value += 1
            print(num.value)
            time.sleep(0.01)
        l.release()
    
    if __name__ == '__main__':
        num = Value('i',100)
        l = Lock()
        p = Process(target=get_money,args=(num,l))
        p.start()
        p1 = Process(target=put_money, args=(num,l))
        p1.start()
        p.join()
        p1.join()
        print(num.value)
    简单加锁的银行存取钱
    from multiprocessing import Process,Lock
    import time
    
    def check(i):
        with open('余票') as f:
            con = f.read()
        print('第%s个人查到余票还剩%s张'%(i,con))
    
    def buy_ticket(i,l):
        l.acquire()# 拿钥匙,锁门
        with open('余票') as f:
            con = int(f.read())
            time.sleep(0.1)
        if con > 0:
            print('33[31m 第%s个人买到票了33[0m'%i)
            con -= 1
        else:
            print('33[32m 第%s个人没有买到票33[0m'%i)
        time.sleep(0.1)# 是指 买完票后,把余票数量重写写入数据库的时间延迟
        with open('余票','w') as f:
            f.write(str(con))
        l.release()# 还钥匙,开门
    
    if __name__ == '__main__':
        l = Lock()
        for i in range(10):
            p_ch = Process(target=check,args=(i+1,))
            p_ch.start()
        for i in range(10):
            p_buy = Process(target=buy_ticket,args=(i+1,l))
            p_buy.start()
    抢票

    学习信号机制

    信号量===多把锁的意思
    from multiprocessing import Semaphore
    
    l = Semaphore(2)
    
    l.acquire()# 拿走1把钥匙,锁上门
    print(123)
    l.acquire()# 拿走1把钥匙,锁上门
    print(456)
    l.release()
    l.acquire()# 拿走1把钥匙,锁上门
    print(789)
    Semaphore信号量
    from multiprocessing import Process,Semaphore
    import time
    import random
    
    def func(i,sem):
        sem.acquire()
        print('第%s个人进入小黑屋,拿了钥匙锁上门' % i)
        time.sleep(random.randint(3,5))
        print('第%s个人出去小黑屋,还了钥匙打开门' % i)
        sem.release()
    
    if __name__ == '__main__':
        sem = Semaphore(5)# 初始化了一把锁5把钥匙,也就是说允许5个人同时进入小黑屋
        # 之后其他人必须等待,等有人从小黑屋出来,还了钥匙,才能允许后边的人进入
        for i in range(20):
            p = Process(target=func,args=(i,sem,))
            p.start()
    小发廊

    sem = Semaphore(n)
    n : 是指初始化一把锁配几把钥匙,一个int型
    拿钥匙,锁门 l.acquire()
    还钥匙,开门 l.release()
    信号量机制比锁机制多了一个计数器,这个计数器是用来记录当前剩余几把钥匙的。
    当计数器为0时,表示没有钥匙了,此时acquire()处于阻塞。
    对于计数器来说,每acquire一次,计数器内部就减1,release一次,计数器就加1



    学习事件机制
    from multiprocessing import Event
    
    e = Event()
    # e.set()
    # e.clear()
    # e.wait()
    # e.is_set()
    
    # e.is_set()是一个阻塞标识
    # e.wait()根据标识随机应变,当标识为true,那么 wait()一下代表非阻塞
    #                                false 那么 wait() 就阻塞了
    print(e.is_set())       # False  不阻塞的 那么e.wait() 就设置为阻塞
    e.set()                 # 将is_set 的bool值变为True,
    e.wait()                # 设置为非阻塞
    print(e.is_set())       # True
    print(123)              # 123
    e.clear()               # 清除阻塞
    print(e.is_set())       # False
    e.wait()                # 阻塞了~
    print(123)               # 便秘出不来了!
    Event事件模块
    • 事件是通过is_set()的bool值,去标识e.wait() 的阻塞状态
    • 当is_set()的bool值为False时,e.wait()是阻塞状态
    • 当is_set()的bool值为True时,e.wait()是非阻塞状态
    • 当使用set()时,是把is_set的bool变为True
    • 当使用clear()时,是把is_set的bool变为False
    from multiprocessing import Process,Event
    import time
    import random
    
    def tra(e):
        '''信号灯函数'''
        # e.set()
        # print('33[32m 绿灯亮! 33[0m')
        while 1:# 红绿灯得一直亮着,要么是红灯要么是绿灯
            if e.is_set():# True,代表绿灯亮,那么此时代表可以过车
                time.sleep(5)# 所以在这让灯等5秒钟,这段时间让车过
                print('33[31m 红灯亮! 33[0m')# 绿灯亮了5秒后应该提示到红灯亮
                e.clear()# 把is_set设置为False
            else:
                time.sleep(5)# 此时代表红灯亮了,此时应该红灯亮5秒,在此等5秒
                print('33[32m 绿灯亮! 33[0m')# 红的亮够5秒后,该绿灯亮了
                e.set()# 将is_set设置为True
    
    def Car(i,e):
        e.wait()# 车等在红绿灯,此时要看是红灯还是绿灯,如果is_set为True就是绿灯,此时可以过车
        print('第%s辆车过去了'%i)
    
    if __name__ == '__main__':
        e = Event()
        triff_light = Process(target=tra,args=(e,))# 信号灯的进程
        triff_light.start()
        for i in range(50):# 描述50辆车的进程
            if i % 3 == 0:
                time.sleep(2)
            car = Process(target=Car,args=(i+1,e,))
            car.start()
    信号灯


    学习生产者消费者模型
    主要用于解耦(耦合度)







  • 相关阅读:
    webuploader多次触发注册
    下载二进制文件
    表格打印
    多个请求下 loading 的展示与关闭
    前进刷新后退不刷新
    页面权限控制和登陆验证
    axios.post 配置formdata提交
    react错误边界
    关于beforeRouterEnter获取不到this
    JS
  • 原文地址:https://www.cnblogs.com/zhuangdd/p/12783120.html
Copyright © 2011-2022 走看看