欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python中使用threading.Event协调线程的运行详解

程序员文章站 2022-05-07 10:08:47
threading.event机制类似于一个线程向其它多个线程发号施令的模式,其它线程都会持有一个threading.event的对象,这些线程都会等待这个事件的“发生”,如果此事件一直不发生,那么这...

threading.event机制类似于一个线程向其它多个线程发号施令的模式,其它线程都会持有一个threading.event的对象,这些线程都会等待这个事件的“发生”,如果此事件一直不发生,那么这些线程将会阻塞,直至事件的“发生”。

对此,我们可以考虑一种应用场景(仅仅作为说明),例如,我们有多个线程从redis队列中读取数据来处理,这些线程都要尝试去连接redis的服务,一般情况下,如果redis连接不成功,在各个线程的代码中,都会去尝试重新连接。

如果我们想要在启动时确保redis服务正常,才让那些工作线程去连接redis服务器,那么我们就可以采用threading.event机制来协调各个工作线程的连接操作:

主线程中会去尝试连接redis服务,如果正常的话,触发事件,各工作线程会尝试连接redis服务。

为此,我们可以写下如下的程序:

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)
 
readis_ready = threading.event()
t1 = threading.thread(target=worker, args=(readis_ready,), name='t1')
t1.start()
 
t2 = threading.thread(target=worker, args=(readis_ready,), name='t2')
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) # simulate the check progress 
readis_ready.set()

运行这个程序:

(t1    ) waiting for redis ready...
(t2    ) waiting for redis ready...
(mainthread) first of all, check redis server, make sure it is ok, and then trigger the redis ready event
(t2    ) redis ready, and connect to redis server and do some work [wed nov 5 12:45:03 2014]
(t1    ) redis ready, and connect to redis server and do some work [wed nov 5 12:45:03 2014]

t1和t2线程开始的时候都阻塞在等待redis服务器启动的地方,一旦主线程确定了redis服务器已经正常启动,那么会触发redis_ready事件,各个工作线程就会去连接redis去做相应的工作。

threading.event的wait方法还接受一个超时参数,默认情况下如果事件一直没有发生,wait方法会一直阻塞下去,而加入这个超时参数之后,如果阻塞时间超过这个参数设定的值之后,wait方法会返回。

对应于上面的应用场景,如果redis服务器一致没有启动,我们希望子线程能够打印一些日志来不断地提醒我们当前没有一个可以连接的redis服务,我们就可以通过设置这个超时参数来达成这样的目的:

import threading
import time
import logging
 
logging.basicconfig(level=logging.debug, format='(%(threadname)-10s) %(message)s',)
 
def worker(event):
  while not event.is_set():
    logging.debug('waiting for redis ready...')
    event.wait(1)
  logging.debug('redis ready, and connect to redis server and do some work [%s]', time.ctime())
  time.sleep(1)
 
readis_ready = threading.event()
t1 = threading.thread(target=worker, args=(readis_ready,), name='t1')
t1.start()
 
t2 = threading.thread(target=worker, args=(readis_ready,), name='t2')
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) # simulate the check progress 
readis_ready.set()

与前面的无限阻塞版本唯一的不同就是,我们在工作线程中加入了一个while循环,直到redis_ready事件触发之后才会结束循环,wait方法调用会在1秒的超时后返回,这样,我们就可以看到各个工作线程在系统启动的时候等待redis_ready的同时,会记录一些状态信息。

以下是这个程序的运行结果:

(t1    ) waiting for redis ready...
(t2    ) waiting for redis ready...
(mainthread) first of all, check redis server, make sure it is ok, and then trigger the redis ready event
(t2    ) waiting for redis ready...
(t1    ) waiting for redis ready...
(t2    ) waiting for redis ready...
(t1    ) waiting for redis ready...
(t2    ) redis ready, and connect to redis server and do some work [wed nov 5 13:55:46 2014]
(t1    ) redis ready, and connect to redis server and do some work [wed nov 5 13:55:46 2014]

这样,我们就可以在等待redis服务启动的同时,看到工作线程里正在等待的情况。

以上这篇python中使用threading.event协调线程的运行详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。