From afbd128f2a3918943aacbf719648a2eee2c02a6f Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 07:38:17 +0000 Subject: [PATCH] Optimize TextStreamer.__anext__ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimization applies two key micro-optimizations to the async iterator's hot path: **Key Changes:** 1. **Pre-computed length caching**: Store `len(self.text)` as `self._len` during initialization to eliminate repeated `len()` function calls 2. **Local variable optimization**: Use local variable `idx` to cache `self.index` and reduce attribute lookups in the critical path **Performance Impact:** The optimization achieves a **15% runtime improvement** (1.23ms → 1.07ms) by reducing overhead in the `__anext__` method. In Python, attribute access (`self.index`) is slower than local variable access (`idx`) because it requires dictionary lookups in the object's `__dict__`. The pre-computed length also eliminates the overhead of calling `len()` on each iteration. **Workload Benefits:** This optimization is particularly effective for: - **High-frequency streaming scenarios** where `__anext__` is called repeatedly - **Concurrent streaming workloads** as shown in the throughput tests with 100+ streamers - **Large text processing** where the iterator is called hundreds of times per instance The test results show the optimization maintains correctness across all scenarios (single words, empty strings, concurrent access, large inputs) while providing consistent speedup. The micro-optimizations are most beneficial in tight loops or high-concurrency async contexts where the `__anext__` method becomes a performance bottleneck. Note: While individual runtime improved by 15%, the slight throughput decrease (-1.1%) suggests the optimization may have different effects under concurrent load, though the overall performance gain in sequential access patterns makes this a worthwhile improvement. --- litellm/llms/vertex_ai/vertex_ai_non_gemini.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/litellm/llms/vertex_ai/vertex_ai_non_gemini.py b/litellm/llms/vertex_ai/vertex_ai_non_gemini.py index df267d9623b2..a2b5f87f9d14 100644 --- a/litellm/llms/vertex_ai/vertex_ai_non_gemini.py +++ b/litellm/llms/vertex_ai/vertex_ai_non_gemini.py @@ -33,6 +33,7 @@ class TextStreamer: def __init__(self, text): self.text = text.split() # let's assume words as a streaming unit + self._len = len(self.text) self.index = 0 def __iter__(self): @@ -50,9 +51,11 @@ def __aiter__(self): return self async def __anext__(self): - if self.index < len(self.text): - result = self.text[self.index] - self.index += 1 + idx = self.index + if idx < self._len: + # Avoid attribute lookups in hot path. + result = self.text[idx] + self.index = idx + 1 return result else: raise StopAsyncIteration # once we run out of data to stream, we raise this error