def throttle(self):
        """Uses time.monotonic() (or time.sleep() if not available) to limit to the desired rate. Should be called once
        per iteration of action which is to be throttled. Returns None unless a custom wait_cmd was specified in the
        constructor in which case its return value is used if a wait was required.
        """
        iterations = self.__iterations
        timestamp = monotonic()
        outdated_threshold = timestamp - self.__interval

        with self.__lock:
            # remove any iterations older than interval
            try:
                while iterations[0] < outdated_threshold:
                    iterations.popleft()
            except IndexError:
                pass
            # apply throttling if rate would be exceeded
            if len(iterations) <= self.__max_iterations:
                iterations.append(timestamp)
                retval = None
            else:
                # wait until oldest sample is too old
                delay = max(0, iterations[0] + self.__interval - timestamp)
                # only notify user about longer delays
                if delay > 1:
                    logger.warning('Send throttling delay (interval=%d, max_iterations=%d): %.2fs', self.__interval,
                                   self.__max_iterations, delay)
                retval = self.__wait_cmd(delay)
                # log actual addition time
                iterations.append(monotonic())

            return retval
Uses time.monotonic() (or time.sleep() if not available) to limit to the desired rate. Should be called once
        per iteration of action which is to be throttled. Returns None unless a custom wait_cmd was specified in the
        constructor in which case its return value is used if a wait was required.