You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[pipeline] support async ops in fused subprocess stages (#1582)
`fuse_subprocess_stages=True` fuses runs of adjacent pipe stages that
share the same isolating-pool (process/interpreter) executor instance
into one nested `Pipeline` that runs inside a worker process,
eliminating the per-stage IPC round-trip. Previously an async op could
never be part of a fused run: `PipeConfig` rejected any `executor` on an
async op, and fusion groups stages purely by executor-instance identity.
An async op between two pool stages therefore split the fusable run in
two, forcing the intermediate value to round-trip (and be pickled)
through the main process.
This lets an async op join a fused run by tagging it with the same
isolating-pool executor as its neighbours. The executor is never used to
run the coroutine (an async op always runs on the event loop) — it is
only the fusion-group key. When fused, the tag is stripped and the op
runs on the worker's own event loop, exactly as fused `path_variants`
async branches already do. When not fused (fusion off, or a lone async
op), the tag is ignored and the op runs on the main loop as before. The
execution engine is unchanged: each worker already rebuilds the
sub-config with the normal `build_pipeline`, which runs a full event
loop.
Builds on the parent diff, which moves the
`_is_isolating_pool`/`_is_interpreter_pool` helpers into
`_common/_convert`; this diff adds their new call sites (notably in
`defs`).
Details:
- `PipeConfig.__post_init__` now allows an isolating-pool executor on an
async op and rejects only non-isolating executors (e.g. a thread pool),
which have no effect on an async op.
- `convert_to_async` ignores the executor for async ops instead of
asserting it is `None`.
- Fusion detection: an async op that now carries an executor flows
through `_fusable_pool_executor` automatically. Inside a `path_variants`
stage, `_scan_variant_pool_executors` ignores an async op's pool tag
instead of treating it as an input-ordered pool-pipe — an async op's
executor is only a fusion-group tag (it runs on the loop, not the pool),
so its `output_order="input"` cannot be broken by pool parallelism and
must not block fusing the same-pool stage. Only a sync input-ordered
pool-pipe still blocks fusion. `_stage_concurrency` counts async ops as
zero worker threads (they run on the loop, not the thread pool).
- `run_pipeline_in_subprocess` strips any executor tag left on an
unfused async op before the op-agnostic executor-hoisting pass, so a tag
never spawns an idle worker pool the op will not use.
A fused async op must be picklable, like any fused stage. This is
documented on `PipelineBuilder.pipe` and in the parallelism guide.
0 commit comments