Source code for torequests.frequency_controller.sync_tools
from threading import Lock
from time import sleep, time
[docs]class Frequency(object):
"""Frequency controller, means concurrent running n tasks every interval seconds.
Basic Usage::
from torequests.frequency_controller.sync_tools import Frequency
from concurrent.futures import ThreadPoolExecutor
from time import time
# limit to 2 concurrent tasks each 1 second
frequency = Frequency(2, 1)
def test():
with frequency:
return time()
now = time()
pool = ThreadPoolExecutor()
tasks = []
for _ in range(5):
tasks.append(pool.submit(test))
result = [task.result() for task in tasks]
assert result[0] - now < 1
assert result[1] - now < 1
assert result[2] - now > 1
assert result[3] - now > 1
assert result[4] - now > 2
assert frequency.to_dict() == {'n': 2, 'interval': 1}
assert frequency.to_list() == [2, 1]
"""
__slots__ = ("gen", "repr", "lock", "__enter__", "n", "interval")
TIMER = time
def __init__(self, n=None, interval=0):
self.n = n
self.interval = interval
self.repr = "Frequency({n}, {interval})".format(n=n, interval=interval)
if n:
self.lock = Lock()
# generator is a little faster than Queue, and using little memory
self.gen = self.generator(n, interval)
self.__enter__ = self._acquire
else:
self.gen = None
self.__enter__ = self.__exit__
[docs] def to_list(self):
"""Return the [self.n, self.interval]"""
return [self.n, self.interval]
[docs] def to_dict(self):
"""Return the dict {'n': self.n, 'interval': self.interval}"""
return {'n': self.n, 'interval': self.interval}
[docs] def generator(self, n=2, interval=1):
q = [0] * n
while 1:
for index, i in enumerate(q):
# or timeit.default_timer()
now = self.TIMER()
diff = now - i
if diff < interval:
sleep(interval - diff)
now = self.TIMER()
q[index] = now
yield now
[docs] @classmethod
def ensure_frequency(cls, frequency):
"""Ensure the given args is Frequency.
:param frequency: args to create a Frequency instance.
:type frequency: Frequency / dict / list / tuple
:return: Frequency instance
:rtype: Frequency
"""
if isinstance(frequency, cls):
return frequency
elif isinstance(frequency, dict):
return cls(**frequency)
else:
return cls(*frequency)
def _acquire(self):
with self.lock:
return next(self.gen)
def __exit__(self, *args):
pass
def __str__(self):
return repr(self)
def __repr__(self):
return self.repr
def __bool__(self):
return bool(self.gen)