• 进程之锁机制, 信号机制, 事件机制


    锁机制:

      l = Lock()

    简单记忆:

      一把锁配一把钥匙.

      拿钥匙, 锁门,   l.acuire()

      还钥匙, 关门,   l.release()

    例子:

      简单模拟购票:

    from multiprocessing import Process,Lock  #  导入multiprocessing模块中的 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)  # 睡眠0.1秒, 模拟一个网络延迟.
        if con > 0: # 当剩余票数大于0的时候, 就能够购票.
            print('33[31m 第%s 个人买到票了33[0m]'%i)
            con -= 1 # 并将票数减去购买的票的数量
        else: # 否则 , 购票失败
            print('33[32m 第%s 个人没买到票了33[0m]'%i)
        time.sleep(0.1) # 睡眠0.1秒, 模拟网络延迟
        with open('余票','w') as f: 以w的模式写入, 覆盖掉之前的数据.
            f.write(str(con))
        l.release() # 结束本次锁机制.  归还钥匙开门, 让其他进程继续进入
    if __name__ == '__main__':
        l = Lock()  # 实例化锁.
        for i in range(10): # 循环开启10个查票进程
            p_ch = Process(target=check, args=(i+1,)) # 实例化是个进程, 并将每次的数字拷贝下来传给子进程
            p_ch.start() # 开启查票的子进程
        for i in range(10): # 循环开启10个购票进程
            p_buy = Process(target=buy_ticket, args=(i+1,l)) # 实例化每次的购票进程, 并将数字, 传递给每次购票进程.
            p_buy.start() # 开启每个购票进程

    简单模拟存取钱:

    from multiprocessing import Lock, Value, Process  # 导入multiprocessing模块中的 Lock方法, Value方法, Process方法.
    import time   # 导入时间模块
    
    def get_money(num,l): # 定义一个取钱函数  其中参数分别是 父进程中定义的卡内总钱数, 和锁机制.
        l.acquire()  # 拿走钥匙, 锁上门, 不允许其他进程进入
        for i in range(100):  # 将 将钱分成100份, 每次取一块.
            num.value -= 1  # 在总钱数上减掉取出来的钱
            print(num.value)  # 打印剩余钱数
            time.sleep(0.01) # 睡眠0.01秒, 模拟网络延迟
        l.release() # 还钥匙, 开门,  让其他进程进入
    
    def put_money(num,l): # 定义一个存钱函数, 参数第一个是卡里剩余钱数, 第二个参数为锁机制 
        l.acquire() # 拿钥匙锁门, 开启锁机制
        for i in range(100):  # 将钱分成100次存, 每次1块
            num.value += 1  # 总钱数累加
            print(num.value)  # 每次操作完以后剩余钱数
            time.sleep(0.01)  # 睡眠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)  会获得取钱, 存钱操作完以后, 最后剩余的钱数

    补充内容:

    一、Value的构造函数:

      Value的初始化非常简单,直接类似Value('d'0.0)即可,具体构造方法为:

      multiprocessing.Value(typecode_or_type*args[, lock])。

      该方法返回从共享内存中分配的一个ctypes 对象,其中typecode_or_type定义了返回的类型。它要么是一个ctypes类型,要么是一个代表ctypes类型的code。比如c_bool和'b'是同样的,因为'b'是c_bool的code。

      ctypes是Python的一个外部函数库,它提供了和C语言兼任的数据类型,可以调用DLLs或者共享库的函数,能被用作在python中包裹这些库。

      *args是传递给ctypes的构造参数

    二、Value的使用

      对于共享整数或者单个字符,初始化比较简单,参照下图映射关系即可。如i = Value('i', 1), c = Value('c', '0')。  

      注意,如果我们使用的code在上表不存在,则会抛出:

        size = ctypes.sizeof(type_)

      TypeError: this type has no size

       如果共享的是字符串,则在上表是找不到映射关系的,就是没有code可用。所以我们需要使用原始的ctype类型

      例如 

      from ctypes import c_char_p

      ss = Value(c_char_p, 'ss')

      ctype类型可从下表查阅

      

      引用自:https://www.cnblogs.com/junyuhuang/p/5539599.html

    信号机制:(信号量)一把锁配多把钥匙.

      信号(signal)-- 进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断

      原来的程序执行流程来处理信号。

    信号量机制比锁机制多了一个计数器, 这个计数器是用来记录当前剩余几把钥匙的.

    当计数器为0时, 表示没有钥匙了, 此时acquire()处于阻塞.

    对于计数器来说, 每次acquire一次, 计数器内部就减掉1, release一次, 计数器就加1.

      sem = Semaphore(num)  # 传入的参数为数字(int类型).

      num 代表的十几把钥匙

      num.acquire()  # 开启信号机制 拿钥匙,锁门
      num.release()  # 结束信号机制

    例子一:

    from multiprocessing import Semaphore,Lock

    # l = Semaphore(4)
    #
    # l.acquire()# 拿走1把钥匙,锁上门
    # print(123)
    # l.acquire()# 拿走1把钥匙,锁上门
    # print(456)
    # l.acquire()# 拿走1把钥匙,锁上门
    # print(789)
    # # l.release()
    # l.acquire()# 拿走1把钥匙,锁上门
    # print(120)

    # 表示初始化的时候, 只有四把要是, 每次调用一次, 
    # 最多进行四次, 指导有人归还钥匙, 才能继续进行



    例子二: 进屋
    from
    multiprocessing import Process,Semaphore import time import random def func(i,sem): sem.acquire() # 每开启1次表示其内部计数器就减少1, 要是少一把. print('第%s个人进入小黑屋,拿了钥匙锁上门' % i) time.sleep(random.randint(3,5)) # 每个人进屋以后, 随机停留的时间. print('第%s个人出去小黑屋,还了钥匙打开门' % i) sem.release() # 每次关闭, 向计数器返还1把钥匙 if __name__ == '__main__': sem = Semaphore(5)# 初始化了一把锁5把钥匙,也就是说允许5个人同时进入小黑屋 # 之后其他人必须等待,等有人从小黑屋出来,还了钥匙,才能允许后边的人进入 for i in range(20): # 表示有20个人在排队 p = Process(target=func,args=(i,sem,)) # 实例化一个进程 p.start()  # 开启一个进程.

    事件机制:

      e = Event()   #  实例化一个事件机制

    常用方法:

      e.is_set()  标识

      e.set()    将is_set()  设为Ture

      e.clear()    将is_set()设置为False

      e.wait()      判断is_set的bool值, 如果bool值为Ture, 则为非阻塞, bool值为False, 则为阻塞

      事件是通过is_set()的bool值, 去标识e.wait() 的状态, 是否为阻塞状态.

      当is_set()的bool值为False的时候, e.wait()的状态是阻塞状态.

      当is_set()的bool值为Ture的时候,  e.wait()的状态是非阻塞状态.

      当使用e.set()的时候, 是把is_set()的bool值变为Ture.

      当使用e.clear()的时候, 是把is_set()的bool值变为False.

      注意: is_set()的bool值默认为False.

    例子:

    红绿信号灯:

    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: # 当是3的倍数的时候, 睡眠三秒.
                time.sleep(2)
            car = Process(target=Car,args=(i+1,e,))# 实例化汽车通过进程
            car.start()  # 开启汽车通过进程.
  • 相关阅读:
    红黑树——面试相关
    汇编常用指令
    c++11 delete禁用函数
    【转】C++可变参数列表处理宏va_list、va_start、va_end的使用
    【转】C/C++函数调用过程分析
    引用的大小
    多线程面试
    2017.08.22网易面试问题记录
    c++ 重载->
    探究Java如何实现原子操作(atomic operation)
  • 原文地址:https://www.cnblogs.com/hfbk/p/9519284.html
Copyright © 2020-2023  润新知