上下文管理器和守护线程
我正在从上下文管理器启动一个守护线程,该线程应该每秒发送一次心跳,但由于它在线程中运行,因此如果发生异常,它不会终止上下文管理器。当心跳停止时,如何在上下文管理器中引发异常?
from contextlib import contextmanager from threading import Thread, Event from time import sleep @contextmanager def plc(): stop_event = Event() try: # Send heartbeat every second hb_t = Thread(target=heartbeat_task, args=(stop_event,), daemon=True) hb_t.start() yield except Exception: raise finally: stop_event.set() hb_t.join() print("Heartbeat stopped") def heartbeat_task(stop_event): value = False while not stop_event.is_set(): value = not value print("Heartbeat: " + str(value)) sleep(1) def main(): with plc(): while True: print("Program running") sleep(5) if __name__ == '__main__': main()
我很难找到这方面的例子。
感谢您的帮助!
正确答案
更新
我已经修改了代码,使其与您发布的代码更加一致。但是:
您提供的代码不一致:heartbeat_task
传递了一个事件,如果设置该事件将导致函数返回。但只有当使用 with plc():
创建的函数 main
中的上下文管理器退出时才会设置它,而这是永远不会的。如果您希望 heartbeat_task
抛出的任何异常将强制上下文管理器退出,然后在函数 plc
中捕获,那么调用 stop_event.set()
的意义何在?如果根据定义,我们仅在 heartbeat_task
不再存在时才到达这里由于异常而运行?
因此,要么您希望 heartbeat_task
无限期地运行,直到引发异常(在这种情况下,没有“停止”事件的意义),要么您希望能够在存在某些条件时停止 heartbeat_task
,但没有这样做的代码。出于演示目的,我假设 main
将有权访问 stop_event
事件,并在某些情况下对其进行设置。否则,它会一直运行,直到检测到 heartbeat_task
不再运行,可能是因为它引发了异常(它正在执行无限循环,所以如果尚未设置停止事件,它怎么可能终止?)。剩下的就是为什么您需要使用上下文管理器。稍后我将提出一个替代方案。
如果您使用多线程池(我们只需要池中的一个线程),那么主线程捕获提交到池的任务抛出的异常就变得很简单:当 multiprocessing.pool.threadpool.apply_async
被调用时返回 multiprocessing.pool.asyncresult
实例,表示未来的完成。当在此实例上调用 get
方法时,您可以从辅助函数 (heartbeat_task
) 获取返回值,或者重新引发辅助函数引发的任何异常。但是我们也可以使用 wait
方法来等待提交任务的完成或经过的时间。然后我们可以使用 ready
方法测试等待 5 秒后提交的任务是否真正完成(由于异常或返回)。如果任务仍在运行,那么我们可以告诉它停止。在此演示中,我强制任务在大约 7 秒后引发异常:
from contextlib import contextmanager from threading import event from multiprocessing.pool import threadpool from time import sleep @contextmanager def plc(): stop_event = event() pool = threadpool(1) # send heartbeat every second async_result = pool.apply_async(heartbeat_task, args=(stop_event,)) yield stop_event, async_result # we only return here if the task is no longer running try: # see if task threw an exception and if so, catch it: async_result.get() except exception as e: print("got exception:", e) finally: pool.close() pool.join() print("heartbeat stopped") def heartbeat_task(stop_event): # for demo purposes, we will force an exception to occur # after approximately 7 seconds: value = false n = 0 while not stop_event.is_set(): value = not value print("heartbeat: " + str(value)) sleep(1) n += 1 if n == 7: raise exception('oops!') def main(): with plc() as tpl: stop_event, async_result = tpl # this function could forcibly cause the heartbeat_task # to complete by calling stop_event.set() # loop while the task is still running while not async_result.ready(): """ if some_condition: stop_event.set() break """ print("program running") # sleep for 5 seconds or until heartbeat_task terminates: async_result.wait(5) if __name__ == '__main__': main()
打印:
program running heartbeat: true heartbeat: false heartbeat: true heartbeat: false heartbeat: true program running heartbeat: false heartbeat: true got exception: oops! heartbeat stopped
使用上下文管理器的替代方法
from threading import Event from multiprocessing.pool import ThreadPool from time import sleep def heartbeat_task(stop_event): value = False n = 0 while not stop_event.is_set(): value = not value print("Heartbeat: " + str(value)) sleep(1) n += 1 if n == 7: raise Exception('Oops!') def main(): stop_event = Event() pool = ThreadPool(1) async_result = pool.apply_async(heartbeat_task, args=(stop_event,)) # Run as long as heartbeat_task is running: while not async_result.ready(): """ if some_condition: stop_event.set() break """ print("Program running") # Sleep for 5 seconds or until heartbeat_task terminates: async_result.wait(5) # Any exception thrown in heartbeat_task will be rethrown and caught here: try: async_result.get() except Exception as e: print("Got exception:", e) finally: pool.close() pool.join() if __name__ == '__main__': main()
以上是上下文管理器和守护线程的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题











Linux终端中查看Python版本时遇到权限问题的解决方法当你在Linux终端中尝试查看Python的版本时,输入python...

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

在使用Python的pandas库时,如何在两个结构不同的DataFrame之间进行整列复制是一个常见的问题。假设我们有两个Dat...

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

Uvicorn是如何持续监听HTTP请求的?Uvicorn是一个基于ASGI的轻量级Web服务器,其核心功能之一便是监听HTTP请求并进�...

在Python中,如何通过字符串动态创建对象并调用其方法?这是一个常见的编程需求,尤其在需要根据配置或运行...
