Performance Tuning
Tune processor configuration for throughput and memory.
All knobs live on ProcessorConfig, passed to the processor at construction time:
import asyncio
import time
from textwrap import dedent
from hother.streamblocks import DelimiterFrontmatterSyntax, Registry, StreamBlockProcessor
from hother.streamblocks.core.processor import ProcessorConfig
from hother.streamblocks_examples.blocks.agent.files import FileOperations
from hother.streamblocks_examples.helpers.simulator import chunked_text_stream
The full field-by-field table lives in the architecture overview; this guide focuses on the trade-offs.
Measure the impact of event flags
Event emission dominates cost on fine-grained streams: with character-level chunking, emit_text_deltas produces one event per chunk. The benchmark below feeds the same 20-block stream through three configurations:
# Generate a large stream with multiple blocks
block_template = dedent("""
!!start
---
id: ops{n:03d}
block_type: files_operations
---
src/file{n:03d}.py:C
!!end
""").strip()
full_text = "\n\n".join(block_template.format(n=i) for i in range(20))
# Character-by-character streaming simulation
def stream():
return chunked_text_stream(full_text, chunk_size=1, delay=0.0)
# Config 1: All events (default)
config_all = ProcessorConfig(
emit_text_deltas=True,
emit_original_events=True,
emit_section_end_events=True,
)
await benchmark_config(config_all, stream, "All events ")
# Config 2: No text deltas (fewer events)
config_no_deltas = ProcessorConfig(
emit_text_deltas=False,
emit_original_events=True,
emit_section_end_events=True,
)
await benchmark_config(config_no_deltas, stream, "No text deltas ")
# Config 3: Blocks only (minimal events)
config_minimal = ProcessorConfig(
emit_text_deltas=False,
emit_original_events=False,
emit_section_end_events=False,
)
await benchmark_config(config_minimal, stream, "Minimal (blocks)")
A representative run (character-by-character streaming):
All events : 1955 events in 0.0203s
No text deltas : 357 events in 0.0065s
Minimal (blocks): 317 events in 0.0049s
Disabling text deltas alone removed over 80% of events here. The trade-off: without TextDeltaEvent you lose character-level updates for live UIs; block events still fire as usual.
Size limits
max_block_size and max_line_length are safety valves against malformed or adversarial streams:
- A block that grows past
max_block_sizeis rejected and surfaces as aBlockErrorEventwith error codeSIZE_EXCEEDED: the stream keeps going. - A line longer than
max_line_lengthis truncated rather than buffered indefinitely.
Raise them when you legitimately stream large blocks (e.g. whole files as block content):
Keep them tight for untrusted input to bound memory per block.
Tips for high-throughput streams
print("\n=== Recommendations ===")
print("- emit_text_deltas=False: Skip per-character events (big reduction)")
print("- emit_original_events=False: Skip raw stream events")
print("- emit_section_end_events=False: Skip metadata/content end events")
print("\nUse minimal config for batch processing, full config for live UIs")
- Start from the minimal config (
emit_text_deltas=False,emit_original_events=False,emit_section_end_events=False) for batch processing; enable flags one by one as features need them. - Set
auto_detect_adapter=Falsewhen feeding plainstrchunks: it skips first-chunk detection and uses the identity adapter directly. - Prefer larger upstream chunks over character-level streaming when latency allows; fewer chunks means fewer delta events and fewer accumulator passes.
- Keep your event loop body cheap: the
async forconsumer is on the hot path, so defer heavy work (I/O, rendering) to tasks or queues.
Next steps
- Events: exactly which events each flag controls.
- Error Handling: handling
SIZE_EXCEEDEDand other block errors. - Logging: observe processor behavior without adding events.