Clarify SyncParallelPipeline docstrings
Rewrite docstrings to more clearly explain what SyncParallelPipeline does: hold all output until every parallel branch finishes, so frames produced in response to a single input are released together.
This commit is contained in:
@@ -4,11 +4,16 @@
|
|||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
"""Synchronous parallel pipeline implementation for concurrent frame processing.
|
"""Synchronized parallel pipeline that holds output until all branches finish.
|
||||||
|
|
||||||
This module provides a pipeline that processes frames through multiple parallel
|
A SyncParallelPipeline fans each inbound frame out to multiple parallel pipelines
|
||||||
pipelines simultaneously, synchronizing their output to maintain frame ordering
|
and waits for every pipeline to finish processing before releasing any of the
|
||||||
and prevent duplicate processing.
|
resulting output frames. This ensures that all frames produced in response to a
|
||||||
|
single input frame are emitted together.
|
||||||
|
|
||||||
|
System frames (except EndFrame) are exempt from this synchronization — they pass
|
||||||
|
straight through without waiting, since they are expected to race ahead of
|
||||||
|
regular data frames.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
@@ -46,20 +51,21 @@ class FrameOrder(Enum):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SyncFrame(ControlFrame):
|
class SyncFrame(ControlFrame):
|
||||||
"""Control frame used to synchronize parallel pipeline processing.
|
"""Sentinel frame used to detect when a parallel pipeline has finished processing.
|
||||||
|
|
||||||
This frame is sent through parallel pipelines to determine when the
|
After sending a real frame into a parallel pipeline, a SyncFrame is sent
|
||||||
internal pipelines have finished processing a batch of frames.
|
behind it. When the SyncFrame emerges from the pipeline's output, we know
|
||||||
|
all output frames for the preceding input have been produced.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SyncParallelPipelineSource(FrameProcessor):
|
class SyncParallelPipelineSource(FrameProcessor):
|
||||||
"""Source processor for synchronous parallel pipeline processing.
|
"""Bookend processor placed at the start of each parallel pipeline.
|
||||||
|
|
||||||
Routes frames to parallel pipelines and collects upstream responses
|
Forwards downstream frames into the pipeline and captures upstream frames
|
||||||
for synchronization purposes.
|
into a queue so the parent SyncParallelPipeline can release them later.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, upstream_queue: asyncio.Queue):
|
def __init__(self, upstream_queue: asyncio.Queue):
|
||||||
@@ -88,10 +94,11 @@ class SyncParallelPipelineSource(FrameProcessor):
|
|||||||
|
|
||||||
|
|
||||||
class SyncParallelPipelineSink(FrameProcessor):
|
class SyncParallelPipelineSink(FrameProcessor):
|
||||||
"""Sink processor for synchronous parallel pipeline processing.
|
"""Bookend processor placed at the end of each parallel pipeline.
|
||||||
|
|
||||||
Collects downstream frames from parallel pipelines and routes
|
Captures downstream output frames into a queue so the parent
|
||||||
upstream frames back through the pipeline.
|
SyncParallelPipeline can release them later, and forwards upstream
|
||||||
|
frames back through the pipeline.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, downstream_queue: asyncio.Queue):
|
def __init__(self, downstream_queue: asyncio.Queue):
|
||||||
@@ -120,15 +127,20 @@ class SyncParallelPipelineSink(FrameProcessor):
|
|||||||
|
|
||||||
|
|
||||||
class SyncParallelPipeline(BasePipeline):
|
class SyncParallelPipeline(BasePipeline):
|
||||||
"""Pipeline that processes frames through multiple parallel pipelines synchronously.
|
"""Fans each input frame to parallel pipelines then holds output until every pipeline finishes.
|
||||||
|
|
||||||
Creates multiple parallel processing paths that all receive the same input frames
|
For each inbound frame the pipeline:
|
||||||
and produces synchronized output. Each parallel path is a separate pipeline that
|
|
||||||
processes frames independently, with synchronization points to ensure consistent
|
|
||||||
ordering and prevent duplicate frame processing.
|
|
||||||
|
|
||||||
The pipeline uses SyncFrame control frames to coordinate between parallel paths
|
1. Sends the frame into every parallel pipeline.
|
||||||
and ensure all paths have completed processing before moving to the next frame.
|
2. Sends a ``SyncFrame`` sentinel behind it in each pipeline.
|
||||||
|
3. Waits until every pipeline has produced its ``SyncFrame``, meaning all
|
||||||
|
output for that input is ready.
|
||||||
|
4. Releases the collected output frames (deduplicating by frame id, since
|
||||||
|
the same frame may emerge from more than one branch).
|
||||||
|
|
||||||
|
System frames (except ``EndFrame``) bypass this mechanism entirely — they are
|
||||||
|
forwarded through each pipeline and pushed immediately, since system frames
|
||||||
|
are expected to race ahead of regular data frames.
|
||||||
|
|
||||||
By default, output frames are pushed in the order they arrive from any pipeline
|
By default, output frames are pushed in the order they arrive from any pipeline
|
||||||
(``FrameOrder.ARRIVAL``). Set ``frame_order=FrameOrder.PIPELINE`` to push frames
|
(``FrameOrder.ARRIVAL``). Set ``frame_order=FrameOrder.PIPELINE`` to push frames
|
||||||
@@ -239,16 +251,11 @@ class SyncParallelPipeline(BasePipeline):
|
|||||||
await asyncio.gather(*[p.cleanup() for p in self._pipelines])
|
await asyncio.gather(*[p.cleanup() for p in self._pipelines])
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
"""Process frames through all parallel pipelines with synchronization.
|
"""Send a frame through all parallel pipelines and release output once all finish.
|
||||||
|
|
||||||
Distributes frames to all parallel pipelines and synchronizes their output
|
System frames (except EndFrame) skip synchronization and pass straight
|
||||||
to maintain proper ordering and prevent duplicate processing. Uses SyncFrame
|
through. All other frames are fanned out to every pipeline, and output is
|
||||||
control frames to coordinate between parallel paths.
|
held until every pipeline signals completion (via SyncFrame).
|
||||||
|
|
||||||
When ``frame_order`` is ``FrameOrder.ARRIVAL``, output frames are pushed in
|
|
||||||
the order they arrive from any pipeline (via a shared queue). When it is
|
|
||||||
``FrameOrder.PIPELINE``, each pipeline collects its output into a separate
|
|
||||||
list and the lists are drained in pipeline definition order.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
frame: The frame to process.
|
frame: The frame to process.
|
||||||
|
|||||||
Reference in New Issue
Block a user