如何为自己的函数或接口实现Timeout超时监听(Python)

2020-03-07  本文已影响0人  越大大雨天

背景

需求背景:
最近收到一个需求,需要为某个接口实现超时检测功能。由于计算量和服务问题,该接口调用返回的时间可能出现过长的情况。需求方希望设定一个超时参数,当函数调用时间超时则返回一个超时的json数据,未超时则正常返回数据。

最终我使用了多线程 + 队列Queue对需求进行了实现,故总结一下本次实现的方法和思路。

原始代码模拟

使用如下代码最简单地还原一下原始接口情景,该代码下,调用task()方法可能存在随机的5~20秒延时才能返回:

import time
import random


# 该接口调用时间可能为5秒到20秒,希望能有一个接口超时检测功能。
# 若延迟在10秒内,则返回正常信息;若延迟大于10秒,则立即返回一个超时的信息。
def task():
    print("start task...")
    start = time.time()
    # 模拟任务随机耗时
    time.sleep(random.randint(5, 20))
    end = time.time()
    print("该次接口调用耗时:{}s".format(end-start))
    return {"status": "succeed"}


if __name__ == '__main__':
    result = task()
    print("返回结果为:{}".format(result))

结果示例,返回结果的时间可能小于10秒也可能大于十秒:

# 结果1
start task...
该次接口调用耗时:16.003031253814697s
返回结果为:{'status': 'succeed'}

# 结果2
start task...
该次接口调用耗时:7.378031253887643s
返回结果为:{'status': 'succeed'}

代码改造,超时监听

在主函数中,实例化一个队列并开启一个多线程任务,使用额外线程运行原有函数中的耗时代码部分,并将最终结果添加到主函数中的队列中。在主线程内,使用get阻塞获取队列中的结果,并传入超时参数,若在超时限制内获取到了结果,则正常返回;若触发了超时异常,则返回超时结果。无论怎样,主线程都将在规定Timeout内进行返回。

代码示例如下:

# 将耗时部分抽离为单独的函数,并接受一个队列参数,该队列为主函数中实例化的队列对象,将最终结果put到该队列中
def time_consuming_code(q):
    start = time.time()
    time.sleep(random.randint(5, 20))
    res = {"status": "succeed"}
    q.put(res)
    end = time.time()
    print("耗时部分后台线程耗时:{}".format(end-start))
    

def task(timeout=10):
    print("start task...")
    start = time.time()
    # 实例化一个队列
    q = Queue()
    # 开启新线程运行耗时部分代码
    t = Thread(target=time_consuming_code, args=(q,))
    # 开启主线程守护,主线程结束则关闭子线程
    t.daemon = True
    t.start()
    # 阻塞超时时间获取队列中的结果,若时间限制内未获取,则捕获异常,返回超时json信息
    try:
        res = q.get(timeout=timeout)
    except Empty:
        res = {"status": "timeout"}
    end = time.time()
    print("该次接口调用耗时:{}s".format(end - start))
    return res


if __name__ == '__main__':
    result = task()
    print("返回结果为:{}".format(result))

输出示例:
主接口耗时最多只会是10秒:

# 正常返回结果:
start task...
耗时部分后台线程耗时:8.000471115112305
该次接口调用耗时:8.000840902328491s
返回结果为:{'status': 'succeed'}

#超时返回结果,超时后耗时任务的子线程被强制关闭,因此看不到子线程耗时输出:
start task...
该次接口调用耗时:10.005242109298706s
返回结果为:{'status': 'timeout'}

总结

以上便是该次利用队列的阻塞获取+多线程实现的超时检测代码demo,你可以将timeout参数单独剥离为配置设置,控制超时设定。
希望能对看了文章的你提供思路。

上一篇 下一篇

猜你喜欢

热点阅读