在python

时间:2015-08-10 14:58:18

标签: python throttling

我有以下类型的代码,但它很慢,因为经常调用report()

import time
import random

def report(values):
    open('report.html', 'w').write(str(values))

values = []

for i in range(10000):
    # some computation
    r = random.random() / 100.
    values.append(r)
    time.sleep(r)
    # report on the current status, but this should not slow things down
    report(values)

在这个说明性的代码示例中,我希望报告是最新的(最多10岁),所以我想限制这个功能。

我可以在报告中分叉,写入当前时间戳,并等待该时间段,并在同时调用报告时使用共享内存时间戳检查。如果是,则终止,否则写入报告。

在Python中有更优雅的方法吗?

2 个答案:

答案 0 :(得分:1)

这是一个装饰器,它将为保护内部函数需要多长时间的参数,如果过早调用则引发异常。

import time
from functools import partial, wraps

class TooSoon(Exception):
  """Can't be called so soon"""
  pass

class CoolDownDecorator(object):
  def __init__(self,func,interval):
    self.func = func
    self.interval = interval
    self.last_run = 0
  def __get__(self,obj,objtype=None):
    if obj is None:
      return self.func
    return partial(self,obj)
  def __call__(self,*args,**kwargs):
    now = time.time()
    if now - self.last_run < self.interval:
      raise TooSoon("Call after {0} seconds".format(self.last_run + self.interval - now))
    else:
      self.last_run = now
      return self.func(*args,**kwargs)

def CoolDown(interval):
  def applyDecorator(func):
    decorator = CoolDownDecorator(func=func,interval=interval)
    return wraps(func)(decorator)
  return applyDecorator

然后:

>>> @CoolDown(10)
... def demo():
...   print "demo called"
...
>>>
>>> for i in range(12):
...   try:
...     demo()
...   except TooSoon, exc:
...     print exc
...   time.sleep(1)
...
demo called
Call after 8.99891519547 seconds
Call after 7.99776816368 seconds
Call after 6.99661898613 seconds
Call after 5.99548196793 seconds
Call after 4.9943420887 seconds
Call after 3.99319410324 seconds
Call after 2.99203896523 seconds
Call after 1.99091005325 seconds
Call after 0.990563154221 seconds
demo called
Call after 8.99888515472 seconds

答案 1 :(得分:0)

这是在Python3中使用闭包对函数进行节流的示例。

import time

def get_current_time_milli():
    return int(round(time.time() * 1000))

def mycallbackfunction():
    time.sleep(0.1)  #mocking some work
    print ("in callback function...")


'''
Throttle a function call using closures.
Don't call the callback function until last invokation is more than 100ms ago.
Only works with python 3. 
Caveat: python 2 we cannot rebind nonlocal variable inside the closure. 

'''

def debouncer(callback, throttle_time_limit=100):

    last_millis = get_current_time_milli()  

    def throttle():
        nonlocal last_millis
        curr_millis = get_current_time_milli()
        if (curr_millis - last_millis) > throttle_time_limit:
            last_millis = get_current_time_milli()
            callback()

return throttle    

# 
myclosure_function = debouncer(mycallbackfunction, 100)

# we are calling myclosure_function 20 times, but only few times, the callback is getting executed. 

# some event triggers this call repeatedly. 
for i in range(20):
    print('calling my closure', myclosure_function(), get_current_time_milli())