Each engine is loaded with one trivial marker worker (a single CloudEvent in,
exactly one CloudEvent out) and then called directly through
IEngine.ProcessAsync in a loop — no WorkManager, API, Redis or
actor turn. This isolates the engine itself: the in-process dispatch, plus
the bridge or subprocess round trip for the engines that use one.
Engines: C# source (Roslyn bridge subprocess), Python (python3 subprocess),
TypeScript (node subprocess), .NET DLL (in-process CoreCLR), native DLL
(in-process, ABI). The Python wheel and npm package share the Python and
TypeScript engines, so they are not separate rows here.
Warmup calls are excluded; the measurement is a single-threaded loop
(one worker = one actor turn), so calls/s is the ceiling one worker can
reach on the runner.
Subprocess engines pay the Unix-socket frame protocol per call; the
in-process .NET/native engines do not, which is why they are one to two
orders of magnitude faster here.
Absolute numbers depend on the runner; compare engines to each other and
a series to its own history, not the two pages to each other.