一、引入event。 
每个线程,都是一个独立运行的个体,并且每个线程的运行状态是无法预测的。

如果一个程序中有很多个线程,程序的其他线程需要判断某个线程的运行状态,来确定自己下一步要执行哪些操作。 
threading模块中的event对象恰好能做到这一点,event对象包含了一个可以通过线程设置的一个信号标志位,它允许线程一直等待某些事件的发生。 
在初始化默认的情况下,event对象中的信号标识被设置为“假”,如果这时,有一个线程等待这个event对象,而这个event对象的信号标志为“假”,那么这个线程就会被一直阻塞下去,直到这个event信号标志为“真”,所有等待这个event对象的线程才会被唤醒。

也就是说,一个线程如果等待的event对象中的信号标志位“真”,这个线程会忽略这个事件(event),继续执行。

二、event对象的常用方法。 
event.isSet():返回event的状态值。 
event.wait(): 当event对象内部的信号标识设置为“假”(False),所有等待这个event对象的线程将会全部被阻塞。

event.set():设置event对象内部的信号标识为“真”(True),所有等待这个event对象的线程将会被唤醒,等待操作系统的调度。

event.clear():恢复event的状态值为False。

三、event使用示例。 
我们来考虑下event对象的应用场景。

假如,在一个程序中,有多个线程需要到redis中来取数据,每个线程都要去尝试着去连接redis服务器,一般情况下,redis如果连接不成功,在所有线程中都需要尝试着去重新连接。 
如果我们想要在程序启动时,先要确保redis服务器工作正常,接着在让其他工作的线程去连接redis服务器,当遇到这种需求的时候,使用event对象就是一个非常不错的选择。 
我们可以使用event机制去让各个工作的线程去做一个简单的通信,主线程去连接redis服务器,如果连接到了,event对象内的信号标识改为真,其余工作的线程就会被唤醒。

示例: 
#!/usr/local/bin/python2.7 
# -*- coding:utf-8 -*- 
import threading 
import time 
import logging 
logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',) 
def worker(event): 
  logging.debug("waiting for redis ready....") 
  event.wait() 
  logging.debug("redis ready,and connect to redis server and do some work %s",time.ctime()) 
  time.sleep(1) 
def main(): 
  redis_ready = threading.Event() 
  t1 = threading.Thread(target=worker,args=(redis_ready,),name="threading-1") 
  t1.start() 
  t2 = threading.Thread(target=worker,args=(redis_ready,),name="threading-2") 
  t2.start() 
  logging.debug("first of all,check redis server, make sure it is ok , and then trigger the redis ready event") 
  time.sleep(3) 
  redis_ready.set() 
if __name__ == '__main__': 
  main()

输出结果: 
(threading-1) waiting for redis ready.... 
(threading-2) waiting for redis ready.... 
(MainThread) first of all,check redis server, make sure it is ok , and then trigger the redis ready event 
(threading-1) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017 
(threading-2) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017

代码分析: 
在上面这段代码中,一共开了三个线程,分别是threading-1和threading-2还有主线程,首先主线程运行了main()函数,产生了一个event对象,这个event对象信号的初始值是False,然后创建了threading-1和threading-2两个线程并且运行,输出一条日志first of all,check redis server, make sure it is ok , and then trigger the redis ready event后sleep 3秒,此时切换到了threading-1,threading-1首先执行了worker函数,输出一次日志,然后执行event.wait方法,当这个event对象的信号标识为False时,threading-1就被阻塞住了,暂时无法执行woker函数后面的内容,当threading-1被阻塞住后,随即切换到threading-2(为什么一定切换到threading-2呢?这是因为主线程还在sleep),threading-2此时也去执行woker函数,同样先输出一条日志waiting for redis ready....,当执行到event.wait时,这个event对象的信号标志位依旧为False,所以执行到这里的时候,threading-2也会被阻塞。 
过了3秒后,MainThread主线程sleep结束,开始向下运行,执行了redis_ready.set()后,我们创建的那个名为redis_ready的event对象中的信号标志会变为True,当这event对象的信号标志变为True之后,之前阻塞的threading-1和threading-2都会被唤醒,继续执行woker函数后面的代码。 
(threading-1) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017 
(threading-2) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017

四、event对象的补充。 
threading.Event的wait方法还接受一个超时参数,默认情况下如果事件一致没有发生,wait方法会一直阻塞下去,而加入这个超时参数之后,如果阻塞时间超过这个参数设定的值之后,wait方法会返回。对应于上面的应用场景,如果Redis服务器一致没有启动,我们希望子线程能够打印一些日志来不断地提醒我们当前没有一个可以连接的Redis服务,我们就可以通过设置这个超时参数来达成这样的目的:

云专线服务,包括外部专线和跨区域专线两种,用户可根据实际情况进行选择。通过专线服务,可以在用户的专用数据中心和云专线之间建立高速、稳定、安全的内网连接,也可以在云专线的不同区域之间实现同一用户的多用户内网连接。

python并发入门(part5 event对象)相关推荐

  1. 11.python并发入门(part5 event对象)

    一.引入event. 每个线程,都是一个独立运行的个体,并且每个线程的运行状态是无法预测的. 如果一个程序中有很多个线程,程序的其他线程需要判断某个线程的运行状态,来确定自己下一步要执行哪些操作. t ...

  2. python 并发编程 多线程 event

    event实现了一个线程通知另外一个线程 线程的一个关键特性是每个线程都是独立运行且状态不可预测. 1.为什么要使用Event对象: 如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的 ...

  3. 11.python并发入门(part9 多进程模块multiprocessing基本用法)

    一.回顾多继承的概念. 由于GIL(全局解释器锁)的存在,在python中无法实现真正的多线程(一个进程里的多个线程无法在cpu上并行执行),如果想充分的利用cpu的资源,在python中需要使用进程 ...

  4. 11.python并发入门(part4 死锁与递归锁)

    一.关于死锁. 死锁,就是当多个进程或者线程在执行的过程中,因争夺共享资源而造成的一种互相等待的现象,一旦产生了死锁,不加人工处理,程序会一直等待下去,这也被称为死锁进程. 下面是一个产生" ...

  5. python观察日志(part5)--判断对象是否为空

    python之判断对象是否为空 判断对象是否为None 要研究这个问题,首先我们要弄清楚,啥是None. ①None表示空值,它是一个特殊 Python 对象, None的类型是NoneType. ② ...

  6. Python使用两个Event对象同步生产者消费者问题

    问题描述:如果缓冲区满则生产者等待,若空则生产者往缓冲区放置物品至缓冲区满:如果缓冲区空则消费者等待,若满则消费者从缓冲区获取物品进行消费直至缓冲区空. 参考代码: 1)首先导入相应的模块 2)编写生 ...

  7. 11.python并发入门(part3 多线程与互斥锁)

    一.锁的概念. 锁,通常被用来实现共享数据的访问,为每一个共享的数据,创建一个Lock对象(一把锁),当需要访问这个共享的资源时,可以调用acquire方法来获取一个锁的对象,当共享资源访问结束后,在 ...

  8. python复制文件夹不阻塞_11.python并发入门(part14阻塞I/O与非阻塞I/O,以及引入I/O多路复用)...

    一.初步了解什么是I/O模型. 1.回顾,用户态与内核态. 操作系统位于应用程序和硬件之间,本质上是一个软件,它由内核以及系统调用组成. 内核:用于运行于内核态,主要作用是管理硬件资源. 系统调用:运 ...

  9. 11.python并发入门(part8 基于线程队列实现生产者消费者模型)

    一.什么是生产者消费者模型? 生产者就是生产数据的线程,消费者指的就是消费数据的线程. 在多线程开发过程中,生产者的速度比消费者的速度快,那么生产者就必须等待消费者把数据处理完,生产者才会产生新的数据 ...

最新文章

  1. 文本文件变身电子表格
  2. python字典中append_零基础入手!Python中字典与集合的使用指南
  3. rust怎么拆自己石墙_房屋征拆:遭遇非法强拆怎么办?如何依法维护自己的权益...
  4. 删除指定天数之前的日期文件夹
  5. idea测试单元错误_不要单元测试错误
  6. java junit mock_使用Mockito进行Java的Mock测试
  7. 前端笔试题【1】--从字符串的第二个字符开始对数组进行排序
  8. 【jQuery笔记Part1】05-jQuery解决冲突
  9. 字节转换,字符串与数字转换
  10. URAL-1991 The battle near the swamp 水题
  11. dnf剑魂buff等级上限_DNF:强化15武器失败,11年老剑魂选择离开,脱坑BUFF都难挽回!...
  12. html5show()函数怎么写,实例:用JavaScript来操作字符串(一些字符串函数)_基础知识...
  13. virt viewer Usbredir USB重定向
  14. iOS 菜鸟钻研动态特性——动态类型、绑定、加载
  15. 全面认识数据指标体系
  16. MAC m1 node vue ui 编译项目时报错:node_modules/.bin/vue-cli-service: Permission denied 解决
  17. Python PDF转高清图片 可设置转前几张
  18. 华为rh2288服务器芯片组,华为RH2288H V2服务器内部介绍
  19. 微信小程序-知晓云等云产品导出excel
  20. Anaconda安装指南

热门文章

  1. linux学习笔记 2013-09-02
  2. sersync进行实时同步数据
  3. Guava 2.2-新集合类型
  4. 软件设计是决定软件性能的关键
  5. linux用户和组的管理详解
  6. 1.微型计算机中主要包括有( ).,《微机原理与应用(1)1351》16秋在线作业2
  7. 【MySQL】MySQL开发注意事项与SQL性能优化步骤
  8. 列了一些自己会但是不怎么精通的编程语言和知识,做个记录,空余时间加强学习...
  9. 查看Linux系统版本的几种方法
  10. 2017-2018-1 20155234《信息安全系统设计基础》第五周学习总结