需求背景

在python代码的实现中,假如我们有一个需要执行时间跨度非常大的for循环,如果在中间的某处我们需要定时停止这个函数,而不停止整个程序。那么初步的就可以想到两种方案:第一种方案是我们先预估for循环或者while中的每一步所需要的运行时间,然后设定在到达某一个迭代次数之后就自动退出循环;第二种方案是,在需要设置超时任务的前方引入超时的装饰器,使得超过指定时间之后自动退出函数执行。这里我们将针对第二种方案,进行展开介绍。

timeout-decorator的安装

在pypi的标准库中也包含有timeout-decorator模块,因此可以通过pip来直接安装:

[dechin@dechin-manjaro timeout]$ python3 -m pip install timeout_decorator
Collecting timeout_decorator
Downloading timeout-decorator-0.5.0.tar.gz (4.8 kB)
Building wheels for collected packages: timeout-decorator
Building wheel for timeout-decorator (setup.py) ... done
Created wheel for timeout-decorator: filename=timeout_decorator-0.5.0-py3-none-any.whl size=5029 sha256=279f8585a08d5e5c87de887492169d1a81e02060c8ea3b62fdd6f062b7f83601
Stored in directory: /home/dechin/.cache/pip/wheels/38/05/4e/161d1463ca145ec1023bd4e5e1f31cbf9239aa8f39a2a2b643
Successfully built timeout-decorator
Installing collected packages: timeout-decorator
Successfully installed timeout-decorator-0.5.0

配置一个超时任务

这里我们先展示示例代码,再展开介绍其中各个模块的含义:

# timeout_test1.py
from tqdm import trange
import sys
import time
import timeout_decorator @timeout_decorator.timeout(int(sys.argv[2]))
def test():
if sys.argv[1] == '--timeout':
for i in trange(3):
time.sleep(1)
print ('>>> {} seconds passed.'.format(i+1))
return 0 if __name__ == '__main__':
try:
test()
except Exception as e:
print ('Timeout Error Catched!')
print (e)
print ("Timeout Task Ended!")

timeout-decorator装饰器的使用

该超时模块采用装饰器的形式来进行调用,使用时先import该模块,然后在需要设置定时任务的函数前添加@timeout_decorator.timeout(3)即可,这里括号中的3表示超时时间设置为3s,也就是3s后该函数就会停止运行。前面写过一篇博客介绍如何自定义一个装饰器,感兴趣的读者可以自行阅读。在上述的用例中,为了使得超时时间的定义更加灵活,我们采取了从用户输入获取参数的方案,具体内容参考下一章节的介绍。

通过sys获取timeout参数

在上述用例的装饰器中,我们看到了int(sys.argv[2])这样的一个参数,这个参数的意思是用户输入命令行的第三个用空格隔开的参数。举例子说,如果用户执行了python3 test.py -t 1,那么这里就会产生三个输入参数:argv[0]就是test.pyargv[1]就是-targv[2]就是1,是一个数组的格式。需要注意的是,argv数组的每一个元素都是字符串格式,如果需要使用数字需要先进行格式转换。这里针对于超时任务的处理,我们指定的执行策略为类似python3 task.py --timeout 5的格式,--timeout后面的数字表示任务执行超时的秒数。如果输入变量格式不正确,或者不满足3个以上的变量输入要求,或者第二个参数不是--timeout,都有可能运行报错。

异常捕获

在定义好超时任务之后,如果达到了设定好的超时时间,系统会给出timeout_decorator.timeout_decorator.TimeoutError报错并结束程序运行。但是我们这里配置超时任务的目的其实是希望在超时任务的函数到达指定时间之后退出,但是不影响其他模块程序的运行,因此这里我们需要对程序给出的报错进行异常捕获,并且通报与抑制该异常。比较简单的方案就是采用except Exception as e的方式,一般Exception最好可以指向指定的报错类型,而不是通用的Exception处理,这有可能带来其他的一些风险。

用例测试

以下按照输入参数的不同,我们先划分为几个模块来分析输出结果以及原因。

超时任务为2s

[dechin@dechin-manjaro timeout]$ python3 timeout_test.py --timeout 2
0%| | 0/3 [00:00<?, ?it/s]>>> 1 seconds passed.
33%|█████████████▋ | 1/3 [00:01<00:03, 1.99s/it]
Timeout Error Catched!
'Timed Out'
Timeout Task Ended!

结果分析:由于我们在程序中给定了一个一共会执行3s的任务,而这里在命令行中我们将超时时间设置为了2s,因此还没执行完程序就抛出并捕获了异常,成功打印了Timeout Task Ended!这一超时任务之外的任务。

超时任务为3s

[dechin@dechin-manjaro timeout]$ python3 timeout_test.py --timeout 3
0%| | 0/3 [00:00<?, ?it/s]>>> 1 seconds passed.
33%|█████████████▋ | 1/3 [00:01<00:02, 1.00s/it]>>> 2 seconds passed.
67%|███████████████████████████▎ | 2/3 [00:02<00:01, 1.50s/it]
Timeout Error Catched!
'Timed Out'
Timeout Task Ended!

结果分析:由于我们在程序中给定了一个一共会执行3s的任务,虽然在命令行的输入参数中我们给定了3s的执行时间,但是最终程序还是没有执行结束并抛出了异常。这是因为sleep(1)并不是精准的1s,也许是1.0000001但是这超出来的时间也会对最终执行的总时间产生影响,况且还有其他模块程序所导致的overlap,因此最后也没有执行完成。而且从进度条来看,上面一个章节中时间设置为3s的时候,其实也只是完成了33%的任务而不是67%的任务,这也是符合我们的预期的。

超时任务为4s

[dechin@dechin-manjaro timeout]$ python3 timeout_test.py --timeout 4
0%| | 0/3 [00:00<?, ?it/s]>>> 1 seconds passed.
33%|█████████████▋ | 1/3 [00:01<00:02, 1.00s/it]>>> 2 seconds passed.
67%|███████████████████████████▎ | 2/3 [00:02<00:01, 1.00s/it]>>> 3 seconds passed.
100%|█████████████████████████████████████████| 3/3 [00:03<00:00, 1.00s/it]
Timeout Task Ended!

结果分析:由于我们在程序中给定了一个一共会执行3s的任务,而在参数输入时配置了4s的超时时间,因此最终任务可以顺利执行完成。这里为了验证上面一个小章节中提到的overlap,我们可以尝试使用系统自带的时间测试模块来测试,如果该程序执行完成之后,一共需要多少的时间:

[dechin@dechin-manjaro timeout]$ time python3 timeout_test.py --timeout 4
0%| | 0/3 [00:00<?, ?it/s]>>> 1 seconds passed.
33%|█████████████▋ | 1/3 [00:01<00:02, 1.00s/it]>>> 2 seconds passed.
67%|███████████████████████████▎ | 2/3 [00:02<00:01, 1.00s/it]>>> 3 seconds passed.
100%|█████████████████████████████████████████| 3/3 [00:03<00:00, 1.00s/it]
Timeout Task Ended! real 0m3.167s
user 0m0.147s
sys 0m0.017s

这里我们就可以看到,其实额定为3s的任务,执行完成需要约3.2s的实际时间,多出来的时间就是所谓的overlap

总结概要

函数的超时设置是一个比较小众使用的功能,可以用于任务的暂停(并非截断)等场景,并且配合上面章节提到的异常捕获和参数输入来使用,会使得任务更加优雅且合理。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/timeout.html

作者ID:DechinPhy

更多原著文章请参考:https://www.cnblogs.com/dechinphy/

使用timeout-decorator为python函数任务设置超时时间的更多相关文章

  1. C# UdpClient 设置超时时间

    /********************************************************************** * C# UdpClient 设置超时时间 * 说明: ...

  2. mongodb3.6 (五)net 客户端访问mongodb设置超时时间踩过的“坑”

    前言 在上一篇文章中,我们有提到net访问mongodb连接超时默认为30秒,这个时间在实际项目中肯定是太长的.而MongoClientSettings 也确是提供了超时属性,如下图: 可实际使用中, ...

  3. Go基础系列:为select设置超时时间

    Go channel系列: channel入门 为select设置超时时间 nil channel用法示例 双层channel用法示例 指定goroutine的执行顺序 After() 谁也无法保证某 ...

  4. GuzzleHttp 请求设置超时时间

    之前调用一个三方的 WEB API,大量的请求超时,导致 PHP 进程被占用完.整个网站一直报 504. 其中一个优化措施就是对三方 API 调用设置超时时间. use GuzzleHttp\Clie ...

  5. Mybatis设置超时时间

    Mybatis设置超时时间 mybatis如果不指定,默认超时时间是不做限制的,默认值为0.mybatis sql配置超时时间有两种方法: 1.全局配置 在mybatis配置文件的settings节点 ...

  6. FFmpeg命令读取RTMP流如何设置超时时间

    子标题:FFmpeg命令录制RTMP流为FLV文件时如何设置超时时间 | FFmpeg命令如何解决录制产生阻塞的问题0x001: 前言 今天在测试程序时遇到两个问题.Q1:ffmpeg录制RTMP流并 ...

  7. winform设置超时时间

    ); //设置超时时间 var completedTask = await Task.WhenAny(new Task(async () => { );//执行的方法示例这里用延迟代替 }), ...

  8. HttpClient 如何设置超时时间

    今天分享一个巨坑,就是 HttpClient.这玩意有多坑呢?就是每个版本都变,近日笔者深受其害. 先看一下代码,我要发送请求调用一个c++接口. public static String doPos ...

  9. 爬虫学习笔记之为什么要设置超时时间,怎么设置(使用selenium)

    一个程序没有设置超时时间,就可以说是一段有缺陷的代码. 读取超时指的就是客户端等待服务器发送请求的时间.(特定地,它指的是客户端要等待服务器发送字节之间的时间.在 99.9% 的情况下这指的是服务器发 ...

随机推荐

  1. Elasticsearch节点下线(退役)and unassigned shards

    一.节点退役当集群中个别节点出现故障预警等情况,需要进行退役工作,即让所有位于该退役节点上的分片的数据分配到其他节点上后,再将此节点关闭并从集群中移除. 1.ES提供了让某个节点上所有数据都移走的功能 ...

  2. Phoenix-4.14-cdh5.14.2与hbase-1.2.0-cdh5.14.2集成测试

    Phoenix介绍: 针对hbase开发的第三方插件,目前已贡献给Apache,顶级项目    Phoenix是构建在HBase上的一个SQL层  可以使用类似于操作mysql的标准sql语句,作为h ...

  3. Redis核心原理-简单动态字符串SDS

    SDS简介 Redis是C语言编写的,但没有使用c语言的字符串结构,而是自己实现了一套简单动态字符串 simple dynamic string 简称SDS,SDS兼容C语言的字符串类型,原理类似Ja ...

  4. RedHat6.1通过配置yum server安装软件包

    1.获取镜像RHEL_6.1\ x86_64\ Disc\ 1 2.配置yum server #cd /etc/yum.repos.d #tar -cvf 20141114bak.tar *.repo ...

  5. 【Linux】ssh互信脚本

    使用互信脚本的时候,需要敲回车,但是shell脚本无法满足,所以需要用到expect脚本 rpm -qa | grep expect 如果没有的话,直接用yum安装即可 yum install exp ...

  6. SDUST数据结构 - 19级期末考试

    判断题: 选择题: 函数题: 6-1 统计二叉树叶子结点个数: 题目: 裁判测试程序样例: #include <stdio.h> #include <stdlib.h> typ ...

  7. 视频画面中实现人脸遮挡教程 - 基于 TensorFlow 实现

    在进行视频通话时,我们往往需要对画面进行一些实时分析,例如识别画面里的人.车.动物等等.这节里我们将使用时信魔方的人脸监视模块实现人脸被手部遮挡的检测,如下图所示效果: 预备知识 时信魔方的客户端使用 ...

  8. SAPLink 非常好用的工具

    对于SAP LINK,如果你想将一个程序完整的保存到本地,包括程序的自定义屏幕.菜单等等,那么请使用这个工具,它能够将一个程序完整的保存下来,并且移植到另一个SAP系统中,用来左程序的迁移和本地保存备 ...

  9. 高效率同步降压变换器,24V转3.3V降压芯片

    PW2312是一个高频,同步,整流,降压,开关模式转换器与内部功率MOSFET.它提供了一个非常紧凑的解决方案,以实现1.5A的峰值输出电流在广泛的输入电源范围内,具有良好的负载和线路调节. PW23 ...

  10. Docker 如何动态给SpringBoot项目传参

    关于SpringBoot配置数据源 在项目开发中,我们往往需要配置多套不同的配置环境例如:本地开发.测试环境.部署环境.每一个环境的数据源配置可能都不同,因此需要写不同的数据源配置.如果用Docker ...