提问人:Qosa 提问时间:8/5/2022 更新时间:11/28/2022 访问量:931
为什么 “event.set()” 不会破坏子线程中的 “while not event.is_set()” 循环?(见代码)
Why does "event.set()" not break a "while not event.is_set()" loop in a sub-thread? (see code)
问:
我正在使用事件在我的主代码和子线程之间进行通信。线程包含一个 while 循环,一旦在主代码中调用 stop_event.set(),该循环就应该退出:
import time
from threading import *
def stream_data(stop_event, new_image_event):
while not stop_event.is_set():
new_image_event.wait()
new_image_event.clear()
# Do some stuff
print('Stuff!')
print('Successfully exited while loop!')
return
if __name__ == '__main__':
# Initialising events
stop_event = Event()
new_image_event = Event()
# Starting the thread
thread = Thread(target=stream_data, args=(stop_event, new_image_event, ))
thread.start()
# Do stuff before setting the stop event, while generating a 'new' new_image_event every 1s
for i in range(5):
new_image_event.set()
time.sleep(1)
# generating the stop event
stop_event.set()
print('stop_event has been set')
# joining back the thread
thread.join()
输出:
Stuff!
Stuff!
Stuff!
Stuff!
Stuff!
stop_event has been set
因此,new_image_event完成了它的工作,最后成功设置了stop_event。但是由于某种原因,这不会中断线程中的while循环,并且永远不会打印“Successfully exited while loop!”。为什么?我该如何解决这个问题(最好不求助于类和/或自我)?
答:
该函数stream_data几乎所有时间都在等待new_image_event,如下所示:
new_image_event.wait()
当您的主线程设置new_image_event时,您将主线程休眠 1 秒钟。这有足够的时间让stream_data醒来,运行 print 语句,返回到循环的顶部,然后再次等待new_image_event。
当你的主线程设置stop_event时,函数stream_data当然在循环中,等待new_image_event。它无法返回到您检查stop_event的循环顶部。没有办法退出循环。
试试这个:
def stream_data(stop_event, new_image_event):
while True:
new_image_event.wait()
new_image_event.clear()
if stop_event.is_set():
break
# Do some stuff
print('Stuff!')
print('Successfully exited while loop!')
评论
stop_event
new_image_event.clear()
您试图满足等待,同时保持响应。正如保罗在诊断你的问题时正确地指出的那样,当你处于另一个事件中时,你不能对这个事件做出回应。然而,他的解决方案是错误的。new_image_event
stop_event
stop_event
wait
我认为您最好的解决方案是利用 的超时机制。根据文档:Event.wait()
当且仅当内部标志已设置为 true 时,此方法返回 True,无论是在等待调用之前还是等待开始之后,因此它将始终返回 True,除非给定超时且操作超时。
换言之,将线程循环更改为以下内容:
def stream_data(stop_event, new_image_event):
while not stop_event.is_set():
# Adjust the following timeout as appropriate. It controls
# the amount of "dead time" before this thread responds
# to `stop_event` if `new_image_event` was not raised
# during the timeout.
if new_image_event.wait(0.1):
new_image_event.clear()
# Do some stuff
print('Stuff!')
time.sleep(0.001) # Breathe, dawg
print('Successfully exited while loop!')
return
这将产生您期望的结果:
Stuff!
Stuff!
Stuff!
Stuff!
Stuff!
stop_event has been set
Successfully exited while loop!
p.s. 循环底部的 1 毫秒睡眠并不是绝对必要的,但我发现它通常很有用,这样线程就有机会“呼吸”,而不是不停地追逐自己的尾巴:)
上一个:从属性对象内触发的事件调用类方法
下一个:工作线程不响应来自主线程的槽调用
评论