为什么"event.set()"不中断子线程中的"while not event.is_set()"循环?(见代码)



我使用事件在主代码和子线程之间进行通信。线程包含一个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循环,并且"已成功退出while循环!"从不打印。为什么?我该如何解决这个问题(最好不要求助于类和/或自我(?

您试图满足对new_image_event的等待,同时保持对stop_event的响应。正如Paul在诊断您的问题时正确指出的那样,当您在wait中处理另一个事件时,您不能对stop_event做出响应。然而,他的解决方案是错误的。

我认为您最好的解决方案是利用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.循环底部的1ms睡眠并不是严格必要的,但我发现它通常很有用,这样线程就有机会"睡眠";呼吸;而不是不停地追逐自己的尾巴:(

函数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!')

最新更新