python异步线程异常处理
我试图在Python中实现超时功能 它的工作原理是使用函数装饰器包装函数,该装饰器将函数作为线程调用,但也会调用“看门狗”线程,该线程将在指定的时间段过后在函数线程中引发异常 它目前适用于不睡眠的线程。在python异步线程异常处理,python,multithreading,exception,asynchronous,ctypes,Python,Multithreading,Exception,Asynchronous,Ctypes,我试图在Python中实现超时功能 它的工作原理是使用函数装饰器包装函数,该装饰器将函数作为线程调用,但也会调用“看门狗”线程,该线程将在指定的时间段过后在函数线程中引发异常 它目前适用于不睡眠的线程。在do\u rand调用期间,我怀疑在time.sleep调用之后以及在执行超出try/except块之后,实际上调用了“异步”异常,因为这将解释由错误启动的线程中的未处理异常。此外,do\u rand调用的错误在调用7秒后生成(持续时间为time.sleep) 我如何“唤醒”一个线程(使用cty
do\u rand
调用期间,我怀疑在time.sleep
调用之后以及在执行超出try/except
块之后,实际上调用了“异步”异常,因为这将解释由错误启动的线程中的未处理异常。此外,do\u rand
调用的错误在调用7秒后生成(持续时间为time.sleep
)
我如何“唤醒”一个线程(使用ctypes?),让它响应异步异常
或者可能是完全不同的方法
代码:
您需要使用睡眠以外的其他方法,或者您需要向另一个线程发送信号以使其醒来
我使用的一个选项是设置一对文件描述符,并使用select或poll而不是sleep,这允许您向文件描述符写入一些内容以唤醒另一个线程。或者,如果您只需要等待睡眠结束,操作就会出错,因为它花费的时间太长,其他一切都不取决于它。问题在于时间。睡眠会阻塞。它很难阻止,所以唯一能真正打断它的就是处理信号。但是带有它的代码变得非常混乱,在某些情况下甚至信号都不起作用(例如,当您正在执行阻塞socket.recv()
,请参见以下内容:)
因此,通常中断线程(而不终止整个进程)是不可能的(更不用说有人可以简单地从线程重写您的信号处理)
但是在这种特殊情况下,您可以使用线程模块中的事件类,而不是使用time.sleep
:
线程1
from threading import Event
ev = Event()
ev.clear()
state = ev.wait(rand_pause) # this blocks until timeout or .set() call
线程2(确保它可以访问相同的ev
实例)
请注意,state
将是事件的内部状态。因此,state==True
将意味着它已使用.set()
解锁,而state==False
将意味着发生超时
在此处阅读有关活动的更多信息:
我如何向线程发送信号?哪个信号?信号
模块将执行此操作。不过,文件描述符方法可能更可靠。我非常希望避免使用文件。所以信号没有任何特别之处,比如,任何will都可以吗?我会避免使用SIGTERM和SIGKILL您可能需要添加一个信号处理程序,以避免信号终止进程。你正依赖于信号传输,这也会中断你所期望的线程的睡眠。这可能不适用于所有操作系统。您的问题是睡眠会停止线程的运行,因此它在退出睡眠之前不会看到引发异常的请求。如果你想要一个可中断的睡眠,你需要使用我提到的选择/轮询机制,或者你可以考虑使用一个条件变量或类似的工具。请参阅线程化
模块。感谢您的回复,但是,本代码的重点是库(希望如此)。因此,我真的不想限制用户代码以排除time.sleep或任何其他阻塞函数的使用do_rand
只是一个测试。我希望我可以使用ctypes(或类似的)修改PyThreadState:@dilbert,正如我所说的:recv()
之类的系统调用可能(并且在阻塞recv()
的情况下也会)无限期地锁定线程。如果不(强制)终止整个过程,您将无法中断它。因此,我认为你会走得更远,这个问题无法解决。但你应该问的问题是:这首先是个问题吗?也许允许阻塞整个线程一点也不坏?在Windows上,只有主线程可以从时间中断。sleep
。它在事件上使用WaitForSingleObject
,而所有其他线程使用不间断Sleep
。在POSIX系统上,time.sleep
使用的select
调用可以使用pthread\u kill
中断,以线程为目标。@freakish,这是一个公平的观点。这段代码的思想是终止长时间运行的任务,这些任务违反了开发人员对执行时间的预期。@eryksun,一方面,感谢您提供的信息,但另一方面,这非常令人不安(关于Windows非主线程)。
from threading import Event
ev = Event()
ev.clear()
state = ev.wait(rand_pause) # this blocks until timeout or .set() call
ev.set() # this will unlock .wait above