```python:inference/core/workflows/execution_engine/v1/executor/execution_data_manager/manager.py
from inference.core.workflows.execution_engine.v1.executor.execution_data_manager.branching_manager import BranchingManager
from inference.core.workflows.execution_engine.v1.executor.execution_data_manager.dynamic_batches_manager import DynamicBatchesManager
from inference.core.workflows.execution_engine.v1.executor.execution_data_manager.execution_cache import ExecutionCache
from networkx import DiGraph
from typing import Any, Dict

class ExecutionDataManager:

    @classmethod
    def init(
        cls,
        execution_graph: DiGraph,
        runtime_parameters: Dict[str, Any],
    ) -> "ExecutionDataManager":
        execution_cache = ExecutionCache.init(execution_graph=execution_graph)
        dynamic_batches_manager = DynamicBatchesManager.init(
            execution_graph=execution_graph,
            runtime_parameters=runtime_parameters,
        )
        branching_manager = BranchingManager.init()
        return cls(
            execution_graph=execution_graph,
            runtime_parameters=runtime_parameters,
            execution_cache=execution_cache,
            dynamic_batches_manager=dynamic_batches_manager,
            branching_manager=branching_manager,
        )

    def __init__(
        self,
        execution_graph: DiGraph,
        runtime_parameters: Dict[str, Any],
        execution_cache: ExecutionCache,
        dynamic_batches_manager: DynamicBatchesManager,
        branching_manager: BranchingManager,
    ):
        self._execution_graph = execution_graph
        self._runtime_parameters = runtime_parameters
        self._execution_cache = execution_cache
        self._dynamic_batches_manager = dynamic_batches_manager
        self._branching_manager = branching_manager
```
```python:inference/core/workflows/execution_engine/v1/executor/flow_coordinator.py
import abc
import networkx as nx
from inference.core.workflows.execution_engine.profiling.core import WorkflowsProfiler
from typing import List, Optional


class StepExecutionCoordinator(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def get_steps_to_execute_next(
        self, profiler: Optional[WorkflowsProfiler] = None
    ) -> Optional[List[str]]:
        pass


class ParallelStepExecutionCoordinator(StepExecutionCoordinator):

    @classmethod
    def init(cls, execution_graph: nx.DiGraph) -> "StepExecutionCoordinator":
        return cls(execution_graph=execution_graph)

    def __init__(self, execution_graph: nx.DiGraph):
        self._execution_graph = execution_graph
        self.__execution_order: Optional[List[List[str]]] = None
        self.__execution_pointer = 0
```
```python:inference/core/workflows/execution_engine/v1/executor/output_constructor.py
from collections import defaultdict
from inference.core.workflows.execution_engine.constants import WORKFLOW_INPUT_BATCH_LINEAGE_ID
from inference.core.workflows.execution_engine.entities.base import JsonField
from inference.core.workflows.execution_engine.v1.compiler.entities import OutputNode
from inference.core.workflows.execution_engine.v1.compiler.utils import construct_output_selector, node_as
from inference.core.workflows.execution_engine.v1.executor.execution_data_manager.manager import ExecutionDataManager
from networkx import DiGraph
from typing import Any, Callable, Dict, List


def construct_workflow_output(
    workflow_outputs: List[JsonField],
    execution_graph: DiGraph,
    execution_data_manager: ExecutionDataManager,
    serialize_results: bool,
    kinds_serializers: Dict[str, Callable[[Any], Any]],
) -> List[Dict[str, Any]]:
    # Maybe we should make blocks to change coordinates systems:
    # https://github.com/roboflow/inference/issues/440
    output_name2indices = {}
    batch_oriented_outputs = set()
    
    for output in workflow_outputs:
        indices = execution_data_manager.get_selector_indices(selector=output.selector)
        output_name2indices[output.name] = indices
        if indices is not None:
            batch_oriented_outputs.add(output.name)
    
    kinds_of_output_nodes = {
        output.name: node_as(
            execution_graph=execution_graph,
            node=construct_output_selector(name=output.name),
            expected_type=OutputNode,
        ).kind
        for output in workflow_outputs
    }
    non_batch_outputs = {}
    for output in workflow_outputs:
        if output.name in batch_oriented_outputs:
            continue
        data_piece = execution_data_manager.get_non_batch_data(selector=output.selector)
        if serialize_results:
            output_kind = kinds_of_output_nodes[output.name]
            data_piece = serialize_data_piece(
                output_name=output.name,
                data_piece=data_piece,
                kind=output_kind,
                kinds_serializers=kinds_serializers,
            )
        non_batch_outputs[output.name] = data_piece
    if not batch_oriented_outputs:
        return [non_batch_outputs]
    outputs_for_generated_lineage = defaultdict(set)
    outputs_for_input_dictated_lineage = set()
    for output in workflow_outputs:
        if output.name not in batch_oriented_outputs:
            outputs_for_input_dictated_lineage.add(output.name)
            continue
        top_level_lineage = node_as(
            execution_graph=execution_graph,
            node=construct_output_selector(name=output.name),
            expected_type=OutputNode,
        ).data_lineage[0]
        if top_level_lineage == WORKFLOW_INPUT_BATCH_LINEAGE_ID:
            outputs_for_input_dictated_lineage.add(output.name)
        else:
            outputs_for_generated_lineage[top_level_lineage].add(output.name)
    dimensionality_for_output_nodes = {
        output.name: node_as(
            execution_graph=execution_graph,
            node=construct_output_selector(name=output.name),
            expected_type=OutputNode,
        ).dimensionality
        for output in workflow_outputs
    }
    results = create_outputs_for_input_induced_lineages(
        output_name2indices=output_name2indices,
        outputs_for_input_dictated_lineage=outputs_for_input_dictated_lineage,
        workflow_outputs=workflow_outputs,
        execution_data_manager=execution_data_manager,
        serialize_results=serialize_results,
        kinds_serializers=kinds_serializers,
        kinds_of_output_nodes=kinds_of_output_nodes,
        non_batch_outputs=non_batch_outputs,
        dimensionality_for_output_nodes=dimensionality_for_output_nodes,
        batch_oriented_outputs=batch_oriented_outputs,
    )
    if len(results) == 0 and len(outputs_for_generated_lineage) > 0:
        results.append({})
    for generated_lineage, outputs_names in outputs_for_generated_lineage.items():
        results_for_outputs_of_generated_lineage = (
            create_outputs_for_generated_lineage_outputs(
                generated_lineage=generated_lineage,
                output_name2indices=output_name2indices,
                outputs_for_generated_lineage=outputs_names,
                workflow_outputs=workflow_outputs,
                execution_data_manager=execution_data_manager,
                serialize_results=serialize_results,
                kinds_serializers=kinds_serializers,
                kinds_of_output_nodes=kinds_of_output_nodes,
                dimensionality_for_output_nodes=dimensionality_for_output_nodes,
            )
        )
        for output in results:
            output.update(results_for_outputs_of_generated_lineage)
    return results
```