-
-
Save gregburek/1441055 to your computer and use it in GitHub Desktop.
import time | |
def RateLimited(maxPerSecond): | |
minInterval = 1.0 / float(maxPerSecond) | |
def decorate(func): | |
lastTimeCalled = [0.0] | |
def rateLimitedFunction(*args,**kargs): | |
elapsed = time.clock() - lastTimeCalled[0] | |
leftToWait = minInterval - elapsed | |
if leftToWait>0: | |
time.sleep(leftToWait) | |
ret = func(*args,**kargs) | |
lastTimeCalled[0] = time.clock() | |
return ret | |
return rateLimitedFunction | |
return decorate | |
@RateLimited(2) # 2 per second at most | |
def PrintNumber(num): | |
print num | |
if __name__ == "__main__": | |
print "This should print 1,2,3... at about 2 per second." | |
for i in range(1,100): | |
PrintNumber(i) |
@oPromessa thanks for sharing and nice job on the logging and example.
Why dont you use a counter instead of a list. Each time the function is called, increment the counter by 1 and reset the counter to 0 when the second or minute has changed
Any updates regarding licensing of these pieces of code?
Note, there are other libraries on PyPI that do this, such as ratelimit
A more simple version but with async compatibility https://gist.github.com/hugokernel/c478d639849e1e772b1395a546100031
I created a similar asyncio version but using the token bucket algorithm for
max number of calls during/time interval which results in a maximum burst rate. it can be combined with the above rate limiter without burst rate..
https://gist.github.com/yeus/dff02dce88c6da9073425b5309f524dd
An extended version of @oPromessa 's utility. Thank you for sharing @oPromessa !
I added Python 3.12 generic type-hinting and support for recursive calls using an RLock
:
from typing import Callable, cast
from functools import wraps
import threading
import time
def rate_limited[T, **P](max_per_second: int) -> Callable[[Callable[P, T]], Callable[P, T]]:
def decorator(fn: Callable[P, T]) -> Callable[P, T]:
lock = threading.RLock()
min_interval = 1.0 / max_per_second
last_time_called = 0.0
@wraps(fn)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
with lock:
nonlocal last_time_called
elapsed = time.perf_counter() - last_time_called
left_to_wait = min_interval - elapsed
if left_to_wait > 0:
time.sleep(left_to_wait)
last_time_called = time.perf_counter()
return fn(*args, **kwargs)
return cast(Callable[P, T], wrapper)
return decorator
Thanks team for sharing this. I've built a class for use in multiprocessing mode. Hope it helps others.