Classes
RenderOrchestrator
Orchestrates page rendering in sequential or parallel modes.
Handles page rendering with support f…
RenderOrchestrator
Orchestrates page rendering in sequential or parallel modes.
Handles page rendering with support for free-threaded Python for true parallelism. Manages thread-local rendering pipelines and integrates with dependency tracking for incremental builds.
Creation:
Direct instantiation: RenderOrchestrator(site)
- Created by BuildOrchestrator during build
- Requires Site instance with pages populated
Attributes
| Name | Type | Description |
|---|---|---|
site |
— | Site instance containing pages and configuration |
_free_threaded |
— | Whether running on free-threaded Python (GIL disabled) |
Relationships |
— |
|
Methods 1
process
Render pages (parallel or sequential).
process
def process(self, pages: list[Page], parallel: bool = True, quiet: bool = False, tracker: DependencyTracker | None = None, stats: BuildStats | None = None, progress_manager: Any | None = None, reporter: Any | None = None, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Render pages (parallel or sequential).
Parameters 9
pages |
list[Page] |
List of pages to render |
parallel |
bool |
Whether to use parallel rendering |
quiet |
bool |
Whether to suppress progress output (minimal output mode) |
tracker |
DependencyTracker | None |
Dependency tracker for incremental builds |
stats |
BuildStats | None |
Build statistics tracker |
progress_manager |
Any | None |
Live progress manager (optional) |
reporter |
Any | None |
|
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
Internal Methods 8
__init__
Initialize render orchestrator.
__init__
def __init__(self, site: Site)
Initialize render orchestrator.
Parameters 1
site |
Site |
Site instance containing pages and configuration |
_render_sequential
Build pages sequentially.
_render_sequential
def _render_sequential(self, pages: list[Page], tracker: DependencyTracker | None, quiet: bool, stats: BuildStats | None, progress_manager: Any | None = None, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Build pages sequentially.
Parameters 7
pages |
list[Page] |
Pages to render |
tracker |
DependencyTracker | None |
Dependency tracker |
quiet |
bool |
Whether to suppress verbose output |
stats |
BuildStats | None |
Build statistics tracker |
progress_manager |
Any | None |
Live progress manager (optional) |
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
_render_parallel
Build pages in parallel for better performance.
Threading Model:
- Creates…
_render_parallel
def _render_parallel(self, pages: list[Page], tracker: DependencyTracker | None, quiet: bool, stats: BuildStats | None, progress_manager: Any | None = None, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Build pages in parallel for better performance.
Threading Model:
- Creates ThreadPoolExecutor with max_workers threads
- max_workers comes from config (default: 4)
- Each thread gets its own RenderingPipeline instance (cached)
- Each pipeline gets its own MarkdownParser instance (cached)
Free-Threaded Python Support (PEP 703):
- Automatically detects Python 3.13t+ with GIL disabled
- ThreadPoolExecutor gets true parallelism (no GIL contention)
- ~1.5-2x faster rendering on multi-core machines
- No code changes needed - works automatically
Caching Strategy:
Thread-local caching at two levels:
1. RenderingPipeline: One per thread (Jinja2 environment is expensive)
2. MarkdownParser: One per thread (parser setup is expensive)
This means with max_workers=N:
- N RenderingPipeline instances created
- N MarkdownParser instances created
- Both are reused for all pages processed by that thread
Performance Example:
With 200 pages and max_workers=10:
10 threads created
10 pipelines created (one-time cost: ~50ms)
10 parsers created (one-time cost: ~100ms)
Each thread processes ~20 pages
Per-page savings: ~5ms (pipeline) + ~10ms (parser) = ~15ms
Total savings: ~3 seconds vs creating fresh for each page
On free-threaded Python (3.14t):
Same setup but ~1.78x faster due to true parallelism
1000 pages in 1.94s vs 3.46s with GIL (515 vs 289 pages/sec)
Parameters 7
pages |
list[Page] |
Pages to render |
tracker |
DependencyTracker | None |
Dependency tracker for incremental builds |
quiet |
bool |
Whether to suppress verbose output |
stats |
BuildStats | None |
Build statistics tracker |
progress_manager |
Any | None |
Live progress manager (optional) |
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
_render_parallel_simple
Parallel rendering without progress (traditional).
_render_parallel_simple
def _render_parallel_simple(self, pages: list[Page], tracker: DependencyTracker | None, quiet: bool, stats: BuildStats | None, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Parallel rendering without progress (traditional).
Parameters 6
pages |
list[Page] |
|
tracker |
DependencyTracker | None |
|
quiet |
bool |
|
stats |
BuildStats | None |
|
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
_render_sequential_with_progress
Render pages sequentially with rich progress bar.
_render_sequential_with_progress
def _render_sequential_with_progress(self, pages: list[Page], tracker: DependencyTracker | None, quiet: bool, stats: BuildStats | None, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Render pages sequentially with rich progress bar.
Parameters 6
pages |
list[Page] |
|
tracker |
DependencyTracker | None |
|
quiet |
bool |
|
stats |
BuildStats | None |
|
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
_render_parallel_with_live_progress
Render pages in parallel with live progress manager.
_render_parallel_with_live_progress
def _render_parallel_with_live_progress(self, pages: list[Page], tracker: DependencyTracker | None, quiet: bool, stats: BuildStats | None, progress_manager: Any, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Render pages in parallel with live progress manager.
Parameters 7
pages |
list[Page] |
|
tracker |
DependencyTracker | None |
|
quiet |
bool |
|
stats |
BuildStats | None |
|
progress_manager |
Any |
|
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
_render_parallel_with_progress
Render pages in parallel with rich progress bar.
_render_parallel_with_progress
def _render_parallel_with_progress(self, pages: list[Page], tracker: DependencyTracker | None, quiet: bool, stats: BuildStats | None, build_context: Any | None = None, changed_sources: set[Path] | None = None) -> None
Render pages in parallel with rich progress bar.
Parameters 6
pages |
list[Page] |
|
tracker |
DependencyTracker | None |
|
quiet |
bool |
|
stats |
BuildStats | None |
|
build_context |
Any | None |
|
changed_sources |
set[Path] | None |
_set_output_paths_for_pages
Pre-set output paths for specific pages before rendering.
Only processes pages…
_set_output_paths_for_pages
def _set_output_paths_for_pages(self, pages: list[Page]) -> None
Pre-set output paths for specific pages before rendering.
Only processes pages that are being rendered, not all pages in the site. This is an optimization for incremental builds where we only render a subset.
Parameters 1
pages |
list[Page] |
Functions
_is_free_threaded
Detect if running on free-threaded Python (PEP 703).
Free-threaded Python (python3.13t+) has the G…
_is_free_threaded
def _is_free_threaded() -> bool
Detect if running on free-threaded Python (PEP 703).
Free-threaded Python (python3.13t+) has the GIL disabled, allowing true parallel execution with ThreadPoolExecutor.
Returns
True if running on free-threaded Python, False otherwisebool
—