"""
Execution engine for parallel processing.

Strictly designed for Linux environments utilizing the 'fork' start method.
Optimized to prevent memory leaks by avoiding Copy-on-Write (CoW) reference
counting issues commonly found in Python multiprocessing.
"""

from multiprocessing import get_context
from typing import Callable, Generator, Any


def run_processes(
    iterable: list, func: Callable, chunksize: int, max_workers: int | None = None
) -> Generator[int, Any, None]:
    """
    Distributes the execution of a function across multiple worker processes.

    WARNING: This implementation strictly relies on the 'fork' context,
    making it incompatible with Windows or macOS default spawn methods.

    Args:
        iterable (list): The list of data chunks to process.
        func (Callable): The target function to execute on each item.
        chunksize (int): The number of items assigned to a worker at once.
        max_workers (int | None, optional): Maximum number of concurrent processes. Defaults to None.

    Yields:
        Generator[int, Any, None]: A continuous stream of results returned by the worker function.
    """
    ctx = get_context("fork")

    # maxtasksperchild=1 ensures that worker processes are terminated and
    # respawned after completing a single task, guaranteeing memory is freed.
    with ctx.Pool(processes=max_workers, maxtasksperchild=1) as pool:
        for result in pool.imap_unordered(func, iterable, chunksize=chunksize):
            yield result
