Loop Rate Limiters
Loop-rate-limiters (current version 1.2.0) is a Python library providing simple frequency regulators for loops, offering an API similar to `rospy.Rate`. It supports both synchronous and asynchronous (asyncio) operations, ensuring code execution at a desired frequency. The library maintains an active development pace with regular patch and minor releases to introduce new features, fix bugs, and improve logging.
Common errors
-
ModuleNotFoundError: No module named 'loop_rate_limiters'
cause The library requires Python 3.9 or higher since version 1.1.0. This error might occur if you are running an older Python version or if the package is not installed correctly.fixEnsure your Python environment is 3.9 or newer (`python --version`). If it is, reinstall the package: `pip install --upgrade loop-rate-limiters`. -
RuntimeError: There is no current event loop in thread '...'
cause When using `AsyncRateLimiter` in versions prior to 1.1.0, this error would occur if the `AsyncRateLimiter` was instantiated or its `sleep()` method called without an active `asyncio` event loop. From v1.1.0, this became a warning instead of an error.fixAlways run asynchronous code, including `AsyncRateLimiter`, within an `asyncio` event loop (e.g., by calling `asyncio.run(your_async_function())`). If on v1.1.0+, check logs for warnings instead of expecting an exception. -
AttributeError: can't set attribute 'period'
cause From version 0.3.0 onwards, attributes like `period`, `slack`, and `next_tick` of `RateLimiter` and `AsyncRateLimiter` are read-only properties.fixThese attributes can only be set during the object's initialization (e.g., `rate = RateLimiter(frequency=10.0)`). If you need to change the frequency, create a new `RateLimiter` instance. -
Lateness warning shows a negative duration (e.g., 'Loop is late by -0.002 s')
cause This was a known bug in version 1.1.0 where the sign of the lateness duration was inverted in warning messages.fixUpgrade to `loop-rate-limiters` version 1.1.1 or higher to resolve this issue and get correctly signed lateness warnings.
Warnings
- breaking Python 3.8 support was removed in version 1.1.0. The library now requires Python 3.9 or newer.
- breaking In `AsyncRateLimiter`, previous versions (pre-1.1.0) would raise a `RuntimeError` if an `asyncio` event loop was not running. From v1.1.0 onwards, this behavior changed to issuing a warning instead of raising an exception.
- breaking Prior to version 0.3.0, attributes like `period` and `slack` on `RateLimiter` objects were writable. From version 0.3.0, these attributes became read-only properties.
- gotcha Versions 1.1.0 had a bug where loop lateness was reported with a negative duration in warning messages. This was fixed in subsequent patch releases.
- gotcha An initialization bug in `AsyncRateLimiter` was fixed in version 1.2.0. Users on older versions might experience unexpected behavior related to the limiter's internal state.
Install
-
pip install loop-rate-limiters
Imports
- RateLimiter
from loop_rate_limiters import RateLimiter
- AsyncRateLimiter
from loop_rate_limiters import AsyncRateLimiter
Quickstart
import asyncio
from loop_rate_limiters import AsyncRateLimiter
import os
async def main():
# Example with an asynchronous rate limiter
# Limits to 400 Hz (iterations per second)
rate = AsyncRateLimiter(frequency=400.0)
for i in range(10):
loop_time = asyncio.get_event_loop().time()
print(f"Async loop iteration {i} at {loop_time:.3f} s")
await rate.sleep()
print("\nSynchronous example (not shown in quickstart, but available):")
from time import perf_counter
from loop_rate_limiters import RateLimiter
sync_rate = RateLimiter(frequency=10.0) # 10 Hz
for i in range(5):
print(f"Sync loop iteration {i} at {perf_counter():.3f} s")
sync_rate.sleep()
if __name__ == "__main__":
asyncio.run(main())