Python使用装饰器和线程限制函数执行时间的方法

前言:

  (不想看废话的可以直接copy尾部的代码)
  在八月上旬的时候,曾经写过一个多线程爬虫。程序在运行时经常莫名的卡死。这令我很是费解,后来才发现,是在请求对方资源时,服务器长时间未返回完数据。导致IO阻塞。
  其实不只是爬虫,很多时候一个函数很可能因为某种不可预知的事情,而有时很可能会卡在某一处,继而函数无法继续执行下去。导致拥塞。
  此时,我们自然而然的会想到如果能写一个装饰器来限制一个函数执行的时间,那么问题也就迎刃而解了。

正文:

  最初,因为我的拥塞是发生在多进程中,我曾经想通过杀死线程的方式来解决问题。然而python中的threading模块中并没有提供这一方法。网上有类似方法,但是比较繁琐。并且非常不建议直接杀死线程(这其中可能关系到资源释放的问题,比如我从队列中取出了一个url, 然而我的进程卡死了,并没有完成相应的任务,我却强行得终止了这个线程,url中的内容未采集,url也没用放回到队列中,岂不是造成了资源的浪费)。后来想到可以直接对函数的运行时间进行限制,这样就省了不少事情。

方法一:

  此方法比较容易理解,写了一个装饰器,看到其中的__wrapper函数,新建了一个守护线程,target是我们需要限制时间的函数。启动守护线程之后,主线程sleep(timer)(timer就是我们设定的函数运行时间)。若在规定的运行时间未结束守护进程(也就是我们需要限制运行时间的函数),则主动抛出异常。(但此种方法有一个弊端,就是如果函数在目标时间内运行完了,由于sleep的原因,整个线程还是会等到sleep(timer)后结束,可能会浪费时间)

#!/usr/bin/env python
#-*- coding:utf-8 -*- 
#Author: Chen
import threading
import time

def time_limited(timer):
    '''
    一个规定函数执行时间的装饰器
    :param timer:
    :return:
    '''
    def wrapper(func):
        def __wrapper(params):
            start_time = time.time()
            #通过设置守护线程强制规定函数的运行时间
            t = threading.Thread(target=func, args=params)
            t.setDaemon(True)
            t.start()
            time.sleep(timer)
            if t.is_alive():
                #若在规定的运行时间未结束守护进程,则主动抛出异常
                raise Exception('Function execution timeout')
            #print time.time()-start_time
        return __wrapper
    return wrapper

第二种:

  此种方法是第一种的升级,改进了函数运行完不结束的弊端

#!/usr/bin/env python
#-*- coding:utf-8 -*- 
#Author: Chen
import time
from threading import Thread

ThreadStop = Thread._Thread__stop#获取私有函数
def time_limited_pri(time_limited):
    def wrapper(func):
        def __wrapper(params):
            class TimeLimited(Thread):
                def __init__(self):
                    Thread.__init__(self)
                def run(self):
                    func(params)
                def _stop(self):
                    if self.is_alive():
                        ThreadStop(self)
                        raise Exception('Function execution overtime')
            t = TimeLimited()
            t.start()
            t.join(timeout=time_limited)
            if t.is_alive():
                t._stop()
                raise Exception('Function execution overtime')
        return __wrapper
    return wrapper
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,314评论 19 139
  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-java.h...
    eddy_wiki阅读 6,605评论 0 14
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 8,060评论 1 18
  • 处女座和上升处女座,在整个9月份,可以用两个字来形容:繁忙。在10月份会继续这种模式,直到中下旬,已经开始累的,再...
    星座论讯阅读 2,507评论 0 0
  • 从未与你饮过冰 零度以下看风景 01 有人说:女孩子是没有爱情的,谁对她好,她就跟谁跑。 你认识我的时候我已经是这...
    肀羽阅读 3,982评论 0 2