Skip to content

perf: create cache items inline, inline the sync close loop, merge build and create (#617) - #626

Merged
lesnik512 merged 1 commit into
mainfrom
perf-617-a
Oct 9, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
perf-617-a

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Part of #617 (items 1, 2 and 6). No public API change.

Summary

  • The cached-factory template creates its cache item inline with cache_items.setdefault(pid, CacheItem(settings=cache_settings)). fetch_cache_item is gone, and with it a frame, a typing.cast and a second dict lookup on a cold miss.
  • cache.close_sync runs its loop inline, shaped like close_async. CacheItem.close_sync and _pending_finalizer are deleted, so AsyncFinalizerInSyncCloseError is no longer raised and caught as control flow.
  • The template's build / create pair is one make(target), and CacheItem.get_or_create(make, target) takes it.

Design decisions

  • get before setdefault stays in the template. A bare setdefault would build a throwaway CacheItem on every warm hit.
  • The template namespace keeps the provider global. No template line reads it, but test_no_alias_frame_is_on_the_stack_during_resolve identifies a generated resolver's frame by it.
  • close_sync keeps its semantics: a finalizer that raises is recorded and cleared; an async finalizer, or a sync one that returns an awaitable, is recorded and left in the creation order for a later close_async. test: pin finalizer ownership and close ordering, mark the threaded cache test (#616) #621's ordering and no-re-finalize tests pin this.
  • The test helper cache_item and the two fetch_cache_item unit tests now go through setdefault and Container.resolve.

Performance

Interleaved A/B against main 5251e1f, 14 rounds, paired median (A/A noise is about ±2.5%):

Scenario Change
G7b request cycle with sync finalizer -8.4%
G7 100 async request cycles -5.7%
G8b cold cached chain -3.5%
Warm resolves (G1 to G5, G9, G16), G6, G8, G10 within ±1%

Test plan

  • just lint-ci
  • full suite, 100% line and branch coverage
  • just test-race

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Details
Benchmark suite Current: 26c29d1 Previous: 5251e1f Ratio
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type 3011310.6937586013 iter/sec (stddev: 1.2512012095284985e-8) 4060335.2829864663 iter/sec (stddev: 7.634302742586644e-9) 1.35
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry 2911409.11065845 iter/sec (stddev: 1.3028471302972171e-8) 4005851.106360469 iter/sec (stddev: 7.754273565687885e-9) 1.38
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve 21287.047357489577 iter/sec (stddev: 0.00004311995728306343) 24745.35471463304 iter/sec (stddev: 0.000041445420158886206) 1.16
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached 16880.74185042475 iter/sec (stddev: 0.00012700461784409043) 18278.097476383533 iter/sec (stddev: 0.000131173741072721) 1.08
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] 398.74091956168996 iter/sec (stddev: 0.000032271405635374285) 516.3258460128818 iter/sec (stddev: 0.00010841971854782612) 1.29
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] 362.91661736364694 iter/sec (stddev: 0.00005306544450240443) 517.1822012756087 iter/sec (stddev: 0.00006460285876223765) 1.43
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] 358.2077146297926 iter/sec (stddev: 0.00011177907445709225) 493.758929188715 iter/sec (stddev: 0.000039071804729130466) 1.38
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] 13133.741325714023 iter/sec (stddev: 0.000008274578522733172) 14665.8263149392 iter/sec (stddev: 0.000005717004260664674) 1.12
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] 6382.1690705579695 iter/sec (stddev: 0.00002406335509611278) 7196.618021322238 iter/sec (stddev: 0.000019156215573622) 1.13
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] 3353.19177331614 iter/sec (stddev: 0.0000424610140736081) 3825.51250869346 iter/sec (stddev: 0.00005433628780087127) 1.14
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[1] 9318.337229712288 iter/sec (stddev: 0.000009706144147775947) 8976.488109105783 iter/sec (stddev: 0.000011084851527566869) 0.96
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[2] 3958.1456443994302 iter/sec (stddev: 0.000021883723811390382) 4201.054779822701 iter/sec (stddev: 0.00001993467309152718) 1.06
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[4] 1885.8380586521948 iter/sec (stddev: 0.000042746218233473515) 1960.5948215940584 iter/sec (stddev: 0.000033267175867689395) 1.04
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[1] 40216.48534025644 iter/sec (stddev: 0.000004999987138687183) 38102.0601793266 iter/sec (stddev: 0.000005590313396803952) 0.95
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[2] 12757.624275222744 iter/sec (stddev: 0.000008938902023117114) 16146.767659235853 iter/sec (stddev: 0.000012167479230268864) 1.27
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[4] 5785.413237608606 iter/sec (stddev: 0.00003247315021013738) 6750.537975695532 iter/sec (stddev: 0.00002661424861407087) 1.17
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container 1637079.0547930493 iter/sec (stddev: 3.35333350876519e-8) 1665108.4027179817 iter/sec (stddev: 2.8386309527174734e-8) 1.02
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope 1681656.956775423 iter/sec (stddev: 2.590218952537419e-8) 1759878.0193341847 iter/sec (stddev: 2.5787028103267435e-8) 1.05
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch 3088.41070125019 iter/sec (stddev: 0.000011193586429702527) 3031.4149662625205 iter/sec (stddev: 0.000023387319206017567) 0.98
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control 57679.70474992205 iter/sec (stddev: 0.000001833286192944345) 57526.68241328694 iter/sec (stddev: 0.0000016379605617544734) 1.00
benchmarks/test_guard_lifecycle.py::test_g7b_request_cycle_sync 336759.485046083 iter/sec (stddev: 6.915685744819809e-7) 368124.0636990991 iter/sec (stddev: 6.309826957276454e-8) 1.09
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale 53793.75356922645 iter/sec (stddev: 0.0000039416983481220865) 53097.22162570917 iter/sec (stddev: 0.0000026636094348803234) 0.99
benchmarks/test_guard_lifecycle.py::test_g13b_teardown_at_scale_async_no_finalizers 521.0136499027076 iter/sec (stddev: 0.0011113545158626058) 507.6803813094065 iter/sec (stddev: 0.0011286539824742231) 0.97
benchmarks/test_guard_resolve.py::test_g1_transient_resolve 2052528.9362947606 iter/sec (stddev: 2.463852757718902e-8) 2380826.3955482235 iter/sec (stddev: 2.5898578590593402e-8) 1.16
benchmarks/test_guard_resolve.py::test_g2_cached_resolve 2788715.662859169 iter/sec (stddev: 1.2045133934030632e-8) 3943320.602454021 iter/sec (stddev: 1.8091879873534426e-8) 1.41
benchmarks/test_guard_resolve.py::test_g3_deep_chain 648183.6662117617 iter/sec (stddev: 1.2016422950357551e-7) 798014.0462849217 iter/sec (stddev: 3.77016391587661e-8) 1.23
benchmarks/test_guard_resolve.py::test_g4_wide_resolve 450446.45324557985 iter/sec (stddev: 4.1596210384218075e-7) 463265.36157194554 iter/sec (stddev: 4.3702670358527684e-7) 1.03
benchmarks/test_guard_resolve.py::test_g5_cross_scope 1736051.2836469363 iter/sec (stddev: 6.249281821110036e-8) 2103202.462252115 iter/sec (stddev: 2.2761041846324313e-8) 1.21
benchmarks/test_guard_resolve.py::test_g9_context_resolve 1331912.936979544 iter/sec (stddev: 1.5671241388394725e-7) 1651467.5911233951 iter/sec (stddev: 1.6590231008033166e-7) 1.24
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve 705423.6035243144 iter/sec (stddev: 9.191825073260599e-8) 799311.2175359981 iter/sec (stddev: 4.6561294279300204e-8) 1.13
benchmarks/test_guard_resolve.py::test_g18_alias_hop 2843945.8110010386 iter/sec (stddev: 1.1655322762871106e-8) 3947024.3028514534 iter/sec (stddev: 8.516061570337632e-9) 1.39
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain 27676.175207227956 iter/sec (stddev: 0.00002123320797967731) 28041.889273323577 iter/sec (stddev: 0.0002420770707622662) 1.01
benchmarks/test_guard_validate.py::test_g11_validate_wide 16467.746715887737 iter/sec (stddev: 0.000027122784326448968) 18788.89642108081 iter/sec (stddev: 0.000026281249842125434) 1.14

This comment was automatically generated by workflow using github-action-benchmark.

@lesnik512
lesnik512 merged commit 502567e into main Oct 9, 2026
11 checks passed
@lesnik512
lesnik512 deleted the perf-617-a branch October 9, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant