前天才讲的知识点,不听讲的人今天就跑来问

今天在读者交流群里面,有同学提到这样一个问题:

这个同学想实现,在代码第35行,如果进入了 if 判断,那么就退出第40-43行对应的 ac 函数。

能问出这个问题,说明这个同学显然没有认真看我的微信公众号。就在几天前我才发了一篇文章:一日一技:Python多线程的事件监控。使用这篇文章里面讲到的方法,就可以轻易实现他的需求。

在那篇文章中,我们讲到了threading.Event,这个东西不仅可以在线程之间使用,也可以在主线程和子线程之间使用。

这个同学的代码不够清晰,我们稍稍修改一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import time
import threading
import datetime

class Monitor(threading.Thread):
def __init__(self, endtime):
super().__init__()
print('ac 函数将会在:', endtime, '停止')
self.endtime = endtime

def run(self):
while True:
now = datetime.datetime.now()
if now > self.endtime:
print('结束主线程')
# TODO: 这里需要做点什么事情
time.sleep(1)

def ac():
while True:
print('主线程正在运行,现在时间', datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
time.sleep(5)


if __name__ == '__main__':
stop_time = datetime.datetime.now() + datetime.timedelta(seconds=60)
monitor = Monitor(stop_time)
monitor.start()
ac()

如果你直接运行上面这段代码,你会发现程序每5秒钟会通过ac函数打印一条字符串,但永远不会停止。现在,我们在 需要在#TODO的位置怎么写代码,才能让程序停止呢?这个时候,我们把threading.Event引入进来。在外面生成并传给子线程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import time
import threading
import datetime

class Monitor(threading.Thread):
def __init__(self, endtime, event):
super().__init__()
self.endtime = endtime
print('ac 函数将会在:', endtime, '停止')
self.event = event

def run(self):
while True:
now = datetime.datetime.now()
if now > self.endtime:
print('结束主线程')
self.event.set()
return
time.sleep(1)

def ac(event):
while not event.is_set():
print('主线程正在运行,现在时间', datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
time.sleep(5)


if __name__ == '__main__':
event = threading.Event()
stop_time = datetime.datetime.now() + datetime.timedelta(seconds=60)
monitor = Monitor(stop_time, event)
monitor.start()
ac(event)

运行效果如下图所示:

当子线程检测到满足结束条件的时候,调用event.set()。主线程里面,ac函数使用一个循环不停检测event.is_set()。一开始event.is_set()始终返回 False,直到event.set()以后,就返回 True。这样一来,ac函数就像是收到了通知,于是可以结束函数的运行了。

如果大家有任何编程上的问题,可以进入未闻 Code 读者交流微信群提问。目前交流群一群、二群已经慢了,三群正在等待更多同学的加入。加我微信号mekingname,备注粉丝群就可以进入。