python 超时处理方法介绍,Eventlet 和 func-timeout

前言

python 超时处理方法介绍,Eventlet 和 func-timeout
有一些场景,需要我们控制程序或者脚本的运行时间。
	自动化用例中的某一个步骤需要在规定时间内完成才算有效;
	使用线程池控制线程运行时,我们不希望每个线程运行时间超过某一值;
	在爬虫时发送的request请求,我们希望在规定时间内无响应则跳过该请求;
	当写入了一条错误的sql查询语句可能会导致该查询语句一直运行,导致其他查询语句阻塞时等等场景
以上场景中,如果我们在程序中设置了超时处理,那将会为我们的程序节约很多运行时间。

1. eventlet

安装: pip install eventlet

eventlet在代码中的使用:

import time
import eventlet                     # 导入eventlet模块

eventlet.monkey_patch()             # 引入patch
with eventlet.Timeout(3, False):    # 设置超时时间3秒
    time.sleep(4)                   # 等待4秒
    print('结果1')                   # 因为等待了4秒,大于超时时间,所以’结果1‘不打印
print('结果2')

# 运行以上程序输出:
# 结果2

with eventlet.Timeout(3, False):    # 设置超时时间3秒
    time.sleep(2)                   # 等待2秒
    print('结果3')                   # 因为等待了2秒,小于超时时间,所以’结果3‘也会打印
print('结果4')

# 运行以上程序输出:
# 结果3
# 结果4

注意:eventlet方法中只要进行了子进程的调用,超时设置就会失效。示例:

import time
import os
import eventlet                     # 导入eventlet模块
from multiprocessing import Process

def my_test(name):
    print('子进程运行中,name={},pid={}'.format(name, os.getpid()))
    time.sleep(10)
    print('子进程已经结束')


if __name__ == '__main__':
    eventlet.monkey_patch()                                 # 引入patch
    with eventlet.Timeout(3, False):                        # 这里设置了超时时间3
        print('父进程:{}'.format(os.getpid()))
        p = Process(target=my_test, args=('test', ))        # 调用了子进程,子进程内有等待10秒的步骤,等待完才会打印’子进程已经结束‘
        print('子进程准备执行---')
        p.start()
        
# 执行以上程序输出:
# 父进程:11548
# 子进程准备执行 - --
# 子进程运行中,name = test,pid = 1996
# 子进程已经结束

从以上示例可以看出,设置的超时时间3秒没有生效。这种情况,我们只能将超时处理步骤加到my_test函数中即可:

def my_test(name):
    print('子进程运行中,name={},pid={}'.format(name, os.getpid()))
    eventlet.monkey_patch()                                 # 引入patch
    with eventlet.Timeout(3, False):
        time.sleep(10)
        print('等待时间结束')
    print('子进程已经结束')

2. func-timeout

	安装:pip install func-timeout

func-timeout 在代码中的使用,func-timeout主要有两中方法:func_timeout,func_set_timeout

2.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('子程序超时')
# 执行以上程序输出:
# 父进程:29908
# 结束
# 子进程运行中,name=test,pid=40280
# 子进程已经结束

# 说明:my_test函数执行需要4s,设置的超时时间大于4s,因此子进程正常执行;若设置my_test函数执行时间大于5s,则报错,代码中尝试了通过捕获异常来让程序正常运行退出,但超时异常时发生在子进程中的,因此捕获异常失败,此时的报错见图1。

图1:
在这里插入图片描述

2.2 func_timeout 用法

import time
import os
from func_timeout import func_timeout
from func_timeout import FunctionTimedOut


def my_test(name):
    print('进程运行中,name={},pid={}'.format(name, os.getpid()))
    time.sleep(6)
    print('进程已经结束')

if __name__ == '__main__':
    try:
        func_timeout(3, my_test, args=('test', ))
    except FunctionTimedOut as e:
        print(e)
        print('进程运行超时')
# 输出:
# 进程运行中,name=test,pid=3364
# Function my_test (args=('test',)) (kwargs={}) timed out # after 3.000000 seconds.

# 进程运行超时
# 说明:func_timeout()第一个参数为超时时间,第二个参数是调用的函数,注意这里只调用函数名,没有(), 第三个参数是调用函数的参数。这里使用的异常捕获也不能解决2.1中的报错问题。
  • 11
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值