Concurrency and Promises¶
Configure Parallel Execution¶
Python API execution is sequential by default. Enable promise-pipelined template calls globally:
or temporarily:
Parallelism changes scheduling, not language results. If sequential and parallel execution produce different values, that is a runtime bug rather than a supported race-dependent mode.
The parallel() Context¶
kedi.parallel() is shorthand for a context override:
Equivalent:
The previous configuration is restored on exit.
Worker Limits¶
max_workers bounds the shared thread pool used for independent model calls.
Pools are process-wide and reused by worker count. Use a positive value.
The CLI/runtime environment also recognizes KEDI_PARALLEL:
- unset, empty,
0,false,no, oroff: sequential; 1,true,yes, oron: parallel with eight workers;- a positive integer: parallel with that worker count;
- a negative integer: sequential;
- another value: configuration error.
An explicit Python API parallel setting supplies the engine used by that
decorated run.
KediPromise¶
In parallel mode, an output field is initially represented internally by a
KediPromise view over the template's shared future:
One model call with several output fields creates one future and one promise view per field. Downstream templates receive dependency edges without blocking the scheduling thread.
Normal substitutions, procedure calls, Python name access, and final query returns resolve at genuine consumption points. Most application code should never observe a promise.
Force a Promise¶
Resolve an intentionally obtained low-level promise:
force() calls .resolve() only for KediPromise; every other value passes
through unchanged. promise.map(fn) creates a derived promise using a
completion callback without consuming another worker slot.
Promise Leaks¶
Promises are deliberately opaque. Using an unresolved promise through
str(), an f-string, comparison, indexing, iteration, arithmetic, attribute
access, hashing, or a call raises KediPromiseLeak.
This is not a normal “value is not ready” condition. It means a promise escaped runtime deferral and reached a concrete-value operation. The loud failure prevents silent serialization or subtly wrong results.
repr(promise) is safe and never resolves. Copy/deep-copy preserves identity;
pickling an unresolved promise raises.
Dataflow Resolution¶
Kedi snapshots the value environment by value when a template is scheduled. Later writes on the main thread do not change that job's inputs.
Inside embedded Python, ordinary bare-name lookup resolves a promise. Advanced
non-resolving dictionary operations such as globals().get("name"),
globals().items(), globals().values(), and dict(globals()) can expose the
raw promise for forwarding. Call kedi.force(...) before concrete use.
At the outermost return, Kedi drains all scheduled jobs, including unconsumed template calls. The first failure is raised; additional concurrent failures are logged.
Thread Safety¶
Parallel mode may call an adapter's synchronous production path concurrently from multiple worker threads. Custom adapters must be thread-safe or serialize internally.
Python tools can also run under adapter concurrency. Protect mutable shared state explicitly. Do not rely on the GIL as an application-level consistency guarantee.