async-lru: Asynchronous LRU Cache for asyncio

2.3.0 · active · verified Sat Mar 28

async-lru is a simple LRU (Least Recently Used) cache implementation designed specifically for asynchronous Python functions within the asyncio ecosystem. It serves as a 100% port of Python's built-in `functools.lru_cache` for `async def` functions, ensuring that multiple concurrent calls to a cached coroutine result in only one execution of the wrapped function. The library is actively maintained, with regular releases addressing bug fixes, performance improvements, and new features, with the latest major version being 2.3.0.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates basic usage of the `alru_cache` decorator with `maxsize`, `ttl` (time-to-live), and `jitter` parameters. It shows how to inspect cache statistics using `cache_info()`, check for cache presence with `cache_contains()`, and explicitly close the cache with `cache_close()` to release resources. Note that `aiohttp` is used for demonstration purposes of an actual async network call.

import asyncio
import aiohttp
from async_lru import alru_cache

@alru_cache(maxsize=32, ttl=10, jitter=2)
async def get_pep(num):
    """Fetches a PEP from python.org, caches the result."""
    resource = f'http://www.python.org/dev/peps/pep-{num:04d}/'
    print(f"Fetching PEP {num}...")
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(resource) as s:
                if s.status == 200:
                    return await s.text()
                return f'Not Found (Status: {s.status})'
        except aiohttp.ClientError as e:
            return f'Network Error: {e}'

async def main():
    print("\n--- First round (misses) ---")
    for n in 8, 290, 308, 320:
        pep = await get_pep(n)
        print(f"PEP {n}: {len(pep) if pep else 'Error'} characters")

    print("\n--- Second round (hits) ---")
    for n in 8, 218, 320:
        pep = await get_pep(n)
        print(f"PEP {n}: {len(pep) if pep else 'Error'} characters")

    print("\n--- Cache Info ---")
    print(get_pep.cache_info())

    print("\n--- Checking cache_contains ---")
    print(f"Cache contains PEP 8: {get_pep.cache_contains(8)}")
    print(f"Cache contains PEP 9991: {get_pep.cache_contains(9991)}")

    # Simulate passage of time for TTL
    print("\n--- Waiting for TTL expiration (10 seconds) ---")
    await asyncio.sleep(10) # Wait for TTL

    print("\n--- After TTL: PEP 8 (should re-fetch) ---")
    pep = await get_pep(8)
    print(f"PEP 8: {len(pep) if pep else 'Error'} characters")
    print(get_pep.cache_info())

    # Closing is optional but highly recommended to release resources
    await get_pep.cache_close()

if __name__ == '__main__':
    # This example requires aiohttp for network requests
    # If aiohttp is not installed, the example will still run but 'get_pep' will fail.
    # pip install aiohttp
    try:
        asyncio.run(main())
    except RuntimeError as e:
        print(f"Caught a runtime error: {e}. This might happen if the event loop is already running.")

view raw JSON →