domains / app-frameworks / python/cpython
Optimize hot-path code
In performance-sensitive code (loops, frequently-called functions, parsers, I/O paths), eliminate redundant work and unnecessary indirection, and validate optimizations with measurements rather than assumptions.
In performance-sensitive code (loops, frequently-called functions, parsers, I/O paths), eliminate redundant work and unnecessary indirection, and validate optimizations with measurements rather than assumptions.
Concretely:
- Hoist loop-invariant computations out of loops. For example, precompute masks/constants once before a loop instead of recalculating them on every iteration (e.g.
mask = self._EVENT_READ | self._EVENT_WRITEcomputed once outsidefor fd, event in fd_event_list:rather than inside it). - Avoid creating redundant intermediate objects. If you already hold a
memoryview, slice it directly instead of wrapping it in anothermemoryviewfirst (buffer.appendleft(b[nbytes:])whenbis already a memoryview, instead ofmemoryview(b)[nbytes:]). - When adding a “fast path” for a common case, make it as broad and efficient as reasonable without sacrificing correctness, e.g. covering
utf-8/utf8encodings generally rather than only ASCII-only strings, so more real-world inputs benefit from the speedup. - Be wary of replacing simple, allocation-free control flow (e.g. a
try/exceptloop) with higher-level abstractions (e.g. genericiter()helpers) purely for readability—if the common/fast path is hit almost every time, extra setup (method binding, exception-type checks, iterator protocol) can measurably regress performance (a reported 40% slowdown in one case). Prefer the implementation that keeps the hot/common path cheap, and benchmark before merging such changes. - Limit unnecessary symbol exposure in compiled/generated code (e.g. mark internal C functions
Py_LOCAL_SYMBOL/staticinstead of exporting them). Unneeded exported symbols can force calls through the PLT instead of direct calls, add linker overhead, and risk symbol interposition between independently built modules.
Always back performance-related changes with profiling or benchmark data when the modification affects a hot path, and prefer the version with the least overhead for the most frequently executed case.