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

锁机制:

  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('\033[31m 第%s 个人买到票了\033[0m]'%i)
        con -= 1 # 并将票数减去购买的票的数量
    else: # 否则 , 购票失败
        print('\033[32m 第%s 个人没买到票了\033[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('\033[32m 绿灯亮! \033[0m')
    while 1:# 红绿灯得一直亮着,要么是红灯要么是绿灯
        if e.is_set():# True,代表绿灯亮,那么此时代表可以过车
            time.sleep(5)# 所以在这让灯等5秒钟,这段时间让车过
            print('\033[31m 红灯亮! \033[0m')# 绿灯亮了5秒后应该提示到红灯亮
            e.clear()# 把is_set设置为False
        else:
            time.sleep(5)# 此时代表红灯亮了,此时应该红灯亮5秒,在此等5秒
            print('\033[32m 绿灯亮! \033[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()  # 开启汽车通过进程.

转载于:https://www.cnblogs.com/hfbk/p/9519284.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值