暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

python Event同步的梳理

小儿来一壶枸杞酒泡茶 2021-05-24
384

之前的有梳理过关于进程的python 多进程间相互协调: Event事件,这里那我们的线程其实是和进程的使用的方式大同小异的。

他们的定义和作用是保持一致的:所以这里不会展开太多关于event的一些细节。

回顾关于进程上的Event:

1 Event 方式同步通信

Event提供一种简单的方法,可以在进程间(也可以是线程间)传递状态信息,实现进程间(线程间)同步通信(不同的进程之间可以利用一些特殊的处理来等待其他进程处理完毕)

Event可以切换设置和未设置状态。通过使用一个可选的超时值,事件对象的用户可以等待其状态从未设置变为设置状态。

事件event运行的机制:

全局定义了一个Flag

  • 如果Flag值为 False,当程序执行event.wait()方法时就会阻塞

  • 如果Flag值为True时,程序执行event.wait()方法时不会阻塞继续执行

事件event几个方法:

  • wait()方法:等待是否阻塞依赖全局的Flag的值。

PS:当调用wait()方法是将进入到阻塞状态,同时会设置阻塞标记为“False”,(待阻塞标记为“True"后才会解除阻塞状态,然后继续当前进程的任务执行,wait是切换当前的状态,转移执行权)

Event 提供了如下方法:

  • is_set():该方法返回 Event 的内部标记是否为True。
  • set():该方法将会把 Event 的内部标记设置为 True,并唤醒【所有处于等待】状态的线程。

ps:当标记保持在True的状态时,线程调用wait()是不会阻塞的。

  • clear():该方法将 Event 的内部标记设置为 False,通常接下来会调用 wait() 方法来阻塞【当前线程】,当前线程进入阻塞,直到其他线程调用set()后来唤醒。
  • wait(timeout=None):该方法会阻塞【当前线程】。

ps:如果内部标志在wait()方法调用时为True,则立即返回,不会阻塞当前线程的执行。进入wait()方法通常前面是调用了clear(),再调用wait()才会启动阻塞的作用。

事件event

在的进程也是一样。上一次我们的进程中看到好像顺序是保持,一次的,其实纯属一种巧合。

进程示例如下:

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     jincheng4
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/5/7
-------------------------------------------------
   修改描述-2021/5/7:         
-------------------------------------------------

全局定义了一个Flag

- 如果Flag值为 False,当程序执行event.wait()方法时就会阻塞

- 如果Flag值为True时,程序执行event.wait()方法时不会阻塞继续执行

### 事件event几个方法:
- wait()方法:等待是否阻塞依赖全局的Flag的值。

- set()方法:将Flag的值改成True

- clear()方法:将Flag的值改成False

- is_set()方法:判断当前的Flag的值


"
""
import multiprocessing,time,random

def restaurant_handle(event):

    print("肯德基开门了!!")
    print("【服务员-1】当前事件状态:",event.is_set())
    print("1、【服务员】请问你要吃点什么吗?。。。")
    time.sleep(random.randint(1,3))
    event.set()#解除阻塞状态
    event.clear()#清除已有的状态
    # 当调用wait()方法是将进入到阻塞状态,同时会设置阻塞标记为“False”,(待阻塞标记为“True"后才会接触阻塞状态)
    event.wait()#等待客人点餐之后,才能进行下一步的后续处理

    print("3、【服务员】你自己一个人这么能吃啊!。。。")
    time.sleep(random.randint(1,3))
    event.set() #解除阻塞状态
    event.clear()  # 之前的状态清空
    event.wait()

    print("5、【服务员】好的,我现在就给你下单,请你稍等。。。")
    time.sleep(random.randint(1,3))
    event.set()  # 解除阻塞状态
    event.clear()  # 之前的状态清空
    event.wait()

    print("7、【服务员】好的,你稍等一下~~~。。。")
    time.sleep(random.randint(1,3))
    event.set()
    # event.clear()
    # event.wait()

    print("8、【服务员】客人你点的:一个鸡腿+一个汉堡+一个这么大的鸡排 已做好了!请慢慢享用!")
    time.sleep(random.randint(1,3))
    # event.set()
    # event.clear()
    event.wait()

    print("11、【服务员】好的,总共消费1000快!。。。")
    time.sleep(random.randint(1, 3))
    event.set()  # 解除阻塞状态
    event.clear()  # 之前的状态清空
    event.wait()

def diners_hangle(event):#食客的处理进程
    print("当前事件状态:", event.is_set())
    event.wait() #等待之前的第一步完成  两个进程所以先阻塞,让另一个执行

    print("2、【客人】我要点一个鸡腿+一个汉堡+一个这么大的鸡排!。。。")
    time.sleep(random.randint(1,3))
    event.set() #解除阻塞状态
    event.clear()#之前的状态清空
    event.wait()#继续等待后续的处理步骤

    print("4、【客人】怎么不可以吗?快下单吧~我都饿的叽里咕噜了~")
    time.sleep(random.randint(1,3))
    event.set()
    event.clear()
    event.wait()

    print("6、【客人】让师傅做快一点。。。")
    time.sleep(random.randint(1,3))
    event.set()
    event.clear()
    event.wait()

    print("9、【客人】好的,我开始吃了~~~~")
    # event.set()
    time.sleep(random.randint(1, 3))

    print("10、【客人】吃完了!服务员,我买单!!!~~~~")
    time.sleep(random.randint(1, 3))
    event.set()
    event.clear()
    event.wait()

    print("12、【客人】这么黑~~1000快!!不给!!我跑了!再见!~~~~")
    event.set()


def main():
    # 定义一个event同步处理,默认是处于阻塞的状态
    event = multiprocessing.Event()
    restaurant_process = multiprocessing.Process(target=restaurant_handle,args=(event,),name="肯德基服务进程")
    diners_process = multiprocessing.Process(target=diners_hangle,args=(event,),name="客人进程")
    restaurant_process.start()
    diners_process.start()
if __name__ == '__main__':
    main()


输出结果为:

D:\ceshi>python jincheng5.py
肯德基开门了!!
【服务员-1】当前事件状态:False
1、【服务员】请问你要吃点什么吗?。。。
当前事件状态:False
2、【客人】我要点一个鸡腿+一个汉堡+一个这么大的鸡排!。。。
3、【服务员】你自己一个人这么能吃啊!。。。
4、【客人】怎么不可以吗?快下单吧~我都饿的叽里咕噜了~
5、【服务员】好的,我现在就给你下单,请你稍等。。。
6、【客人】让师傅做快一点。。。
7、【服务员】好的,你稍等一下~~~。。。
8、【服务员】客人你点的:一个鸡腿+一个汉堡+一个这么大的鸡排 已做好了!请慢慢享用!
9、【客人】好的,我开始吃了~~~~
10、【客人】吃完了!服务员,我买单!!!~~~~
11、【服务员】好的,总共消费1000快!。。。
12、【客人】这么黑~~1000快!!不给!!我跑了!再见!~~~~


PS:上面的输出就结果看着是按顺序,但是其实再某种情况是不会按顺序执行,!

修改为线程形式:

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------  
-------------------------------------------------
"
""
import multiprocessing,time,random
import threading
# 创建event事件
event = threading.Event()


def restaurant_handle(event):

    print("肯德基开门了!!")
    print("【服务员-1】当前事件状态:",event.is_set())
    print("1、【服务员】请问你要吃点什么吗?。。。")
    time.sleep(random.randint(1,3))
    event.set()#解除阻塞状态
    event.clear()#清除已有的状态
    # 当调用wait()方法是将进入到阻塞状态,同时会设置阻塞标记为“False”,(待阻塞标记为“True"后才会接触阻塞状态)
    event.wait()#等待客人点餐之后,才能进行下一步的后续处理

    print("3、【服务员】你自己一个人这么能吃啊!。。。")
    time.sleep(random.randint(1,3))
    event.set() #解除阻塞状态
    event.clear()  # 之前的状态清空
    event.wait()

    print("5、【服务员】好的,我现在就给你下单,请你稍等。。。")
    time.sleep(random.randint(1,3))
    event.set()  # 解除阻塞状态
    event.clear()  # 之前的状态清空
    event.wait()

    print("7、【服务员】好的,你稍等一下~~~。。。")
    time.sleep(random.randint(1,3))
    event.set()
    # event.clear()
    # event.wait()

    print("8、【服务员】客人你点的:一个鸡腿+一个汉堡+一个这么大的鸡排 已做好了!请慢慢享用!")
    time.sleep(random.randint(1,3))
    # event.set()
    # event.clear()
    event.wait()

    print("11、【服务员】好的,总共消费1000快!。。。")
    time.sleep(random.randint(1, 3))
    event.set()  # 解除阻塞状态
    event.clear()  # 之前的状态清空
    event.wait()

def diners_hangle(event):#食客的处理进程
    print("当前事件状态:", event.is_set())
    event.wait() #等待之前的第一步完成  两个进程所以先阻塞,让另一个执行

    print("2、【客人】我要点一个鸡腿+一个汉堡+一个这么大的鸡排!。。。")
    time.sleep(random.randint(1,3))
    event.set() #解除阻塞状态
    event.clear()#之前的状态清空
    event.wait()#继续等待后续的处理步骤

    print("4、【客人】怎么不可以吗?快下单吧~我都饿的叽里咕噜了~")
    time.sleep(random.randint(1,3))
    event.set()
    event.clear()
    event.wait()

    print("6、【客人】让师傅做快一点。。。")
    time.sleep(random.randint(1,3))
    event.set()
    event.clear()
    event.wait()

    print("9、【客人】好的,我开始吃了~~~~")
    # event.set()
    time.sleep(random.randint(1, 3))

    print("10、【客人】吃完了!服务员,我买单!!!~~~~")
    time.sleep(random.randint(1, 3))
    event.set()
    event.clear()
    event.wait()

    print("12、【客人】这么黑~~1000快!!不给!!我跑了!再见!~~~~")
    event.set()


def main():

    # event = multiprocessing.Event()
    # restaurant_process = multiprocessing.Process(target=restaurant_handle,args=(event,),name="肯德基服务进程")
    # 创建并初始化线程
    restaurant_thread = threading.Thread(target=restaurant_handle, args=(event,), name="肯德基服务进程", )
    diners_thread = threading.Thread(target=diners_hangle, args=(event,), name="客人进程", )
    # diners_process = multiprocessing.Process(target=diners_hangle,args=(event,),name="客人进程")
    # restaurant_process.start()
    #  全局内置标志Flag,将标志Flag 设置为 True,通知在等待状态(wait)的线程恢复运行;

    # 启动线程
    restaurant_thread.start()
    diners_thread.start()

    restaurant_thread.join()
    diners_thread.join()


if __name__ == '__main__':
    main()

输出结果为:

肯德基开门了!!
【服务员-1】当前事件状态:False
1、【服务员】请问你要吃点什么吗?。。。
当前事件状态:False
2、【客人】我要点一个鸡腿+一个汉堡+一个这么大的鸡排!。。。
3、【服务员】你自己一个人这么能吃啊!。。。
4、【客人】怎么不可以吗?快下单吧~我都饿的叽里咕噜了~
5、【服务员】好的,我现在就给你下单,请你稍等。。。
6、【客人】让师傅做快一点。。。
7、【服务员】好的,你稍等一下~~~。。。
8、【服务员】客人你点的:一个鸡腿+一个汉堡+一个这么大的鸡排 已做好了!请慢慢享用!9、【客人】好的,我开始吃了~~~~

11、【服务员】好的,总共消费1000快!。。。
10、【客人】吃完了!服务员,我买单!!!~~~~


后面输出执行的时候,看到是不一样的顺序!所以这个地方说明了有可能当event.set()的时候,当前线程又抢回执行权了!所以导致顺序乱了!

个人其他博客地址

简书:https://www.jianshu.com/u/d6960089b087

掘金:https://juejin.cn/user/2963939079225608

小钟同学 | 文 【原创】| QQ:308711822

  • 1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。
  • 2:关于文章内容,有部分内容参考自互联网整理,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。


文章转载自小儿来一壶枸杞酒泡茶,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论