我需要实现一个函数,该函数监视正在运行的作业的状态,直到作业完成。类似这样的东西:
def monitor_job(job_id):
ended = False
while not ended:
ended = check_if_ended(job_id)
time.sleep(5)
print('ended')
现在,我想允许用户使用Ctrl-C中断循环,在这种情况下,我想优雅地停止调用stop_job()
函数的作业。然而,这个函数是异步的,它只是提交一个停止作业的请求,这可能需要一些时间才能完成。因此,在这个调用之后,我想继续while循环,等待作业结束。这里有一个尝试:
def monitor_job(job_id):
keybreaks = False
ended = False
while not ended:
# (...)
try:
ended = check_if_ended(job_id)
time.sleep(5)
except KeyboardInterrupt:
# break after a second keybreak
if keybreaks:
raise
keybreaks = True
stop_job(job_id)
print('ended')
在这个解决方案中,我不喜欢的是,如果碰巧在try
之外(例如在(...)
处(触发Ctrl-C,那么异常将不会被捕获,作业也不会正常停止。
有没有一个好的方法来正确处理这个问题,避免这种时间问题
我想到了一些解决方案,比如:在except
块中复制while循环,这并不优雅;或者将try
置于while
循环之外,然后在except
中回调monitor_job()
,但随后Ctrl-C可能在函数调用期间发生。
确实有可能Ctrl-C
发生在(...)
。但它只是一个非常小机会。
如果你想绝对确定,你可以使用以下片段:
def monitor_job(job_id, first_call=True):
ended = False
try:
if first_call:
monitor_job(job_id, first_call=False)
while not ended:
ended = check_if_ended(job_id)
time.sleep(5)
except KeyboardInterrupt:
if first_call:
raise
它还使用了类似您所建议的递归,但不是在except块中,而是在try块中。因此,当您点击Ctrl-C
时,首先退出对monitor_job(first_call=False)
的内部调用,只有在第二个Ctrl-C
之后才退出外部函数。
这是我能想出的最优雅的解决方案。