-
Notifications
You must be signed in to change notification settings - Fork 63
feat: microoptimize _LRUCacheWrapper.__call__
#683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
BobTheBuidler
wants to merge
17
commits into
aio-libs:master
Choose a base branch
from
BobTheBuidler:call
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
68ca039
feat: microoptimize `_LRUCacheWrapper.__call__`
BobTheBuidler 89da95d
Merge branch 'master' into call
BobTheBuidler 8fec92d
feat: benchmarks
BobTheBuidler f7f7a1f
Merge branch 'call' of https://github.com/BobTheBuidler/async-lru int…
BobTheBuidler 79e7b0b
Update requirements-dev.txt
Dreamsorcerer f849a05
Update requirements.txt
Dreamsorcerer c1b5fe9
Update requirements.txt
Dreamsorcerer 205652e
Update tests/benchmarks/test_bench_async_lru.py
BobTheBuidler c30878e
Update test_bench_async_lru.py
BobTheBuidler 549a1ce
Merge branch 'master' into call
BobTheBuidler 5f8e75d
Update test_bench_async_lru.py
BobTheBuidler 10fff06
fix attribute err
BobTheBuidler b833d0f
Merge branch 'call' of https://github.com/BobTheBuidler/async-lru int…
BobTheBuidler a4eaf2f
remove unused mark
BobTheBuidler d9818eb
Merge branch 'master' into call
BobTheBuidler 303f9d5
Delete tests/benchmarks/test_bench_async_lru.py
BobTheBuidler bf06643
Merge branch 'master' into call
BobTheBuidler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| name: CodSpeed Benchmarks | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - master | ||
| - '[0-9].[0-9]+' | ||
| pull_request: | ||
| branches: | ||
| - master | ||
| - '[0-9].[0-9]+' | ||
|
|
||
| jobs: | ||
| benchmark: | ||
| name: Run CodSpeed Benchmarks (Python ${{ matrix.python-version }}) | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| cache: 'pip' | ||
| cache-dependency-path: '**/requirements*.txt' | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| pip install -r requirements-dev.txt | ||
| pip install . | ||
|
|
||
| - name: Run CodSpeed benchmarks | ||
| run: | | ||
| pytest --codspeed --codspeed-upload | ||
| env: | ||
| CODSPEED_TOKEN: ${{ secrets.CODSPEED_TOKEN }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,140 @@ | ||
| import asyncio | ||
| import pytest | ||
| from async_lru import alru_cache | ||
|
|
||
| pytestmark = pytest.mark.codspeed | ||
|
|
||
| # Bounded cache (LRU) | ||
| @alru_cache(maxsize=128) | ||
| async def cached_func(x): | ||
| return x | ||
|
|
||
| @alru_cache(maxsize=16, ttl=0.01) | ||
| async def cached_func_ttl(x): | ||
| return x | ||
|
|
||
| # Unbounded cache (no maxsize) | ||
| @alru_cache() | ||
| async def cached_func_unbounded(x): | ||
| return x | ||
|
|
||
| @alru_cache(ttl=0.01) | ||
| async def cached_func_unbounded_ttl(x): | ||
| return x | ||
|
|
||
| async def uncached_func(x): | ||
| return x | ||
|
|
||
| # Bounded cache benchmarks | ||
| @pytest.mark.asyncio | ||
| async def test_cache_hit_benchmark(benchmark): | ||
| await cached_func(42) | ||
| async def hit(): | ||
| await cached_func(42) | ||
| await benchmark.asyncio(hit) | ||
|
|
||
| @pytest.mark.asyncio | ||
BobTheBuidler marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| async def test_cache_miss_benchmark(benchmark): | ||
| async def miss(): | ||
| await cached_func(object()) | ||
| await benchmark.asyncio(miss) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_fill_eviction_benchmark(benchmark): | ||
| keys = list(range(256)) | ||
| async def fill(): | ||
| for k in keys: | ||
| await cached_func(k) | ||
| await benchmark.asyncio(fill) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_clear_benchmark(benchmark): | ||
| await cached_func(1) | ||
| async def clear(): | ||
| await cached_func.cache_clear() | ||
| await benchmark.asyncio(clear) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_ttl_expiry_benchmark(benchmark): | ||
| await cached_func_ttl(99) | ||
| await asyncio.sleep(0.02) | ||
| async def ttl_expire(): | ||
| await cached_func_ttl(99) | ||
| await benchmark.asyncio(ttl_expire) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_invalidate_benchmark(benchmark): | ||
| await cached_func(123) | ||
| async def invalidate(): | ||
| await cached_func.cache_invalidate(123) | ||
| await benchmark.asyncio(invalidate) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_info_benchmark(benchmark): | ||
| await cached_func(1) | ||
| async def info(): | ||
| cached_func.cache_info() | ||
| await benchmark.asyncio(info) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_uncached_func_benchmark(benchmark): | ||
| async def raw(): | ||
| await uncached_func(42) | ||
| await benchmark.asyncio(raw) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_concurrent_cache_hit_benchmark(benchmark): | ||
| await cached_func(77) | ||
| async def concurrent_hit(): | ||
| await asyncio.gather(*(cached_func(77) for _ in range(10))) | ||
| await benchmark.asyncio(concurrent_hit) | ||
|
|
||
| # Unbounded cache benchmarks | ||
| @pytest.mark.asyncio | ||
| async def test_cache_hit_unbounded_benchmark(benchmark): | ||
| await cached_func_unbounded(42) | ||
| async def hit(): | ||
| await cached_func_unbounded(42) | ||
| await benchmark.asyncio(hit) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_miss_unbounded_benchmark(benchmark): | ||
| async def miss(): | ||
| await cached_func_unbounded(object()) | ||
| await benchmark.asyncio(miss) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_clear_unbounded_benchmark(benchmark): | ||
| await cached_func_unbounded(1) | ||
| async def clear(): | ||
| await cached_func_unbounded.cache_clear() | ||
| await benchmark.asyncio(clear) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_ttl_expiry_unbounded_benchmark(benchmark): | ||
| await cached_func_unbounded_ttl(99) | ||
| await asyncio.sleep(0.02) | ||
| async def ttl_expire(): | ||
| await cached_func_unbounded_ttl(99) | ||
| await benchmark.asyncio(ttl_expire) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_invalidate_unbounded_benchmark(benchmark): | ||
| await cached_func_unbounded(123) | ||
| async def invalidate(): | ||
| await cached_func_unbounded.cache_invalidate(123) | ||
| await benchmark.asyncio(invalidate) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_cache_info_unbounded_benchmark(benchmark): | ||
| await cached_func_unbounded(1) | ||
| async def info(): | ||
| cached_func_unbounded.cache_info() | ||
| await benchmark.asyncio(info) | ||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_concurrent_cache_hit_unbounded_benchmark(benchmark): | ||
| await cached_func_unbounded(77) | ||
| async def concurrent_hit(): | ||
| await asyncio.gather(*(cached_func_unbounded(77) for _ in range(10))) | ||
| await benchmark.asyncio(concurrent_hit) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably also want this in a separate PR in order to see the change this PR produces..