Python函数超时,用装饰器解决

2018-07-25 15:40:41 浏览数 (1)

使用场景

我们在自定义一个函数后,会调用这个函数来完成我们想要的功能。 就拿爬虫来举例,你发送请求,服务器给你响应,但是有可能服务器没有给你任何数据,无论是他识别了爬虫、还是服务器繁忙什么原因,这个时候,你的爬虫就会一直等待响应,这个时候就会非常浪费资源,还会造成程序阻塞。

好在requests和scrapy有自定义timeout时间,例如:在requests中这样写

代码语言:javascript复制
requests.post(url, headers=headers, data=data, proxies=proxies, timeout=15)

在scrapy自定义下载超时时间DOWNLOAD_TIMEOUT = 15

但是,以上所说的仅仅是爬虫,实际中还会有各种各样的情况,在大佬指点下我知道了一个超级好用的函数装饰器 func_timeout

这么好的项目竟然没有关注~

func_timeout

安装:pip install func_timeout

使用:在你的函数前加上装饰器,如下:

代码语言:javascript复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
from func_timeout import func_set_timeout

@func_set_timeout(1)
def task():
    while True:
        print('hello world')
        time.sleep(1)

if __name__ == '__main__':
    task()

output:

代码语言:javascript复制
hello world
Traceback (most recent call last):
  File "/home/test_.py", line 13, in <module>
    task()
  File "/home/usr/python36/lib/python3.6/site-packages/func_timeout/dafunc.py", line 185, in <lambda>
    return wraps(func)(lambda *args, **kwargs : func_timeout(defaultTimeout, func, args=args, kwargs=kwargs))
  File "/home/usr/python36/lib/python3.6/site-packages/func_timeout/dafunc.py", line 101, in func_timeout
    raise FunctionTimedOut('', timeout, func, args, kwargs)
func_timeout.exceptions.FunctionTimedOut: Function task (args=()) (kwargs={}) timed out after 1.000000 seconds.

func_timeout将在指定的参数的线程中运行指定的函数,直到返回,引发异常或超时。如果存在返回或异常,则将正常返回。

可以看到使用方法很简单,直接加上想要的超时时间即可。但是会抛出异常,终止你的程序。官方提供的捕获异常方法。

代码语言:javascript复制
from func_timeout import func_timeout, FunctionTimedOut

...

try:

    doitReturnValue = func_timeout(5, doit, args=('arg1', 'arg2'))

except FunctionTimedOut:
    print ( "doit('arg1', 'arg2') could not complete within 5 seconds and was terminated.n")
except Exception as e:
    # Handle any exceptions that doit might raise here

多线程中使用

那么问题来了,在使用多线程时效果如何?

在做实验时,开启多个线程去执行任务,任务里有些是超时的,抛出错误后会终端主进程,也就是该程序关闭,可以使用异常捕获。如:

代码语言:javascript复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from func_timeout import func_set_timeout
import time
import func_timeout

@func_set_timeout(1)
def task():
    while True:
        print('hello world')
        time.sleep(1)


if __name__ == '__main__':
    try:
        task()
    except func_timeout.exceptions.FunctionTimedOut:
        print('task func_timeout')

output:

代码语言:javascript复制
hello world
task func_timeout

这样就可以不用中断主程序,可以继续执行后面的任务,也可以在超时后加上重试等功能,这就看自己需要了。

最后给大家一个福利,最近发现一个Pycharm的配色,仿制Sublime的 ,看起来非常舒服,地址 simoncos/pycharm-monokai

如果有推荐的主题,欢迎留言指出 ~~~

0 人点赞