Skip to content

Avoid quadratic copying when decoding large batch results - #2060

Open
itsrayeedscodespace wants to merge 1 commit into
anthropics:mainfrom
itsrayeedscodespace:perf/jsonl-linear-buffer
Open

itsrayeedscodespace wants to merge 1 commit into
anthropics:mainfrom
itsrayeedscodespace:perf/jsonl-linear-buffer

Conversation

@itsrayeedscodespace

Copy link
Copy Markdown

Large batch-result records repeatedly copy the growing JSONL buffer because both decoders append each chunk to immutable bytes. BaseAPIResponse feeds these decoders 64-byte chunks, so decoding a long completion has quadratic copying cost.

Use bytearray.extend() and clear the buffer after decoding each record in both sync and async paths. json.loads accepts bytearray directly. The public API and chunking remain unchanged.

On Apple M5 CPU, Python 3.11.18, httpx2 2.16.0 and Pydantic 2.14.3, measured through client.messages.batches.results() / its async counterpart using MockTransport, real response chunking and typed results. Medians of five warmed calls, alternating baseline/candidate order; no live API/network calls:

Text in one result Sync before → after Async before → after
1 KiB 0.262 → 0.261 ms 0.271 → 0.273 ms
16 KiB 0.326 → 0.302 ms 0.335 → 0.312 ms
256 KiB 8.372 → 0.999 ms 8.332 → 1.086 ms
1024 KiB 123.843 → 3.230 ms 125.099 → 3.604 ms

The 1 MiB sync samples ranged 122.2–124.8 ms before and 3.17–3.46 ms after. Small-record costs were effectively unchanged. This measures SDK CPU work with synthetic payloads; network-limited throughput is not claimed.

Validation: 44 tests passed across JSONL decoders and GA/beta batch-results API paths; Ruff lint/format, changed-file Pyright (0 errors), and git diff --check passed. Added fragmented Unicode/escaped-newline records at 1/64/4096-byte boundaries, with and without a trailing newline and with a following record to check buffer reset.

Searched open/closed JSONL, JSONLDecoder, bytearray, quadratic/buffer PRs and commit history. This addresses record buffering, separate from the SSE accumulation work in #1663/#2022, newline handling in #1778 and error cleanup in #1932/#2007/#2049. Those changes touch related code but solve different problems. This generated/persisted module may need a generator-side equivalent.

AI assistance was used for implementation and verification.

@itsrayeedscodespace
itsrayeedscodespace requested a review from a team as a code owner November 11, 2026 23:42

This branch has not been deployed

No deployments
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