因为某个需求,需要在程序运行的时候防止超时。在网上搜了以下发现有3种方法
1.@func_set_timeout这个注解
实测可以用,但是用起来比较麻烦,因为这个超时后会跑出异常,可以直接注解在函数上但不能注解在单条语句上,我设想的是把超时和异常同时处理,这个会抛出新的异常不太符合我的需求
# func_set_timeout作为装饰器使用,来作为目标函数的超时处理方式
import time
import os
from func_timeout import func_set_timeout
@func_set_timeout(5)
def my_test(name):
print('子进程运行中,name={},pid={}'.format(name, os.getpid()))
time.sleep(4)
print('子进程已经结束')
if __name__ == '__main__':
print('父进程:{}'.format(os.getpid()))
try:
p = Process(target=my_test, args=('test', ))
p.start()
except TimeoutError as e:
print('子程序超时')
2.多进程/多限制的.join
比如下面的代码
import time
import threading
def worker():
print('worker start')
time.sleep(10)
print('worker end')
t = threading.Thread(target=worker)
t.start()
# 等待线程结束,不能超过5秒
t.join(5)
if t.is_alive():
print('worker overtime')
else:
print('worker finished')
实测发现运行结果是这样,到了5秒提示overtime但是程序继续运行,然后到了10秒程序运行结束,虽然有超时的效果但是和我设想的还是有区别,我想的是时间到了你就别继续运行了
3.使用eventlet.Timeout来实现,实测下来这个是最符合我需求的,时间到了直接跳出,加一个timeout的变量就能知道是否超时了。美中不足就是必须加一条语句,eventlet.monkey_patch(),简单搜索了下发现这个属于程序在运行时动态对已有代码进行修改,而不需要修改原始代码的一个热补丁。
使用了eventlet后,同时处理超时和异常的代码如下
"""
用于处理函数超时的情况,同时记录程序异常
"""
import eventlet
class PyTimer:
"""
用于在处理异常的同时防止程序超时
"""
def __init__(self, max_time=5):
"""
初始化
"""
# 必须有这条代码
eventlet.monkey_patch()
self.errors = ""
# 最大超时的秒数
self.max_time = max_time
def set_max_time(self,new_time):
"""
设置新的超时秒数
"""
self.max_time=new_time
def count_time(self, function, *args):
"""
运行函数,记录异常,同时超时跳出
"""
return_result = None
timeout = True
current_error = ""
try:
with eventlet.Timeout(self.max_time, False): # 设置超时时间为5秒
return_result = function(*args)
timeout = False
except Exception as e:
current_error = str(e) + "\n"
finally:
if timeout:
current_error += function.__name__ + "超时\n"
print(current_error)
self.errors += current_error
return return_result
def get_errors(self):
"""
获取报错信息
"""
return self.errors
if __name__ == '__main__':
def long_fun(a, b):
import time
print(a, b)
time.sleep(20)
my_timer = PyTimer()
my_timer.count_time(long_fun, 1, 2)