# Executors

> USearch for C#

An executor owns host threads or device streams; an index owns entries.
Keeping them apart is what lets one pool serve several indexes, and what makes the cost of spawning visible at the line that spawns.

One factory per C constructor, each taking only what its hardware has: `ForVram` has no thread count because a single host thread drives one stream per device.

```csharp
using Executor threads = Executor.ForRam(threads: 8);             // Zero derives 7/8 of the cores
using Executor rings = Executor.ForNvme(threads: 4);              // One submission ring apiece
using Executor streams = Executor.ForVram(scratchLimit: 1 << 30); // One stream per device
using Executor shared = Executor.OnPool(forkUnionPool);           // Borrows another library's threads

threads.Drain(Mood.Spinning);                                     // Waits out the holding call, then keeps spinning
```

Each factory also names where its shards go, which is how a dual-socket or multi-GPU box is reached.

```csharp
using Executor domains = Executor.ForRam(16, memoryDomains: [0, 1]);  // One shard per NUMA node
using Executor devices = Executor.ForVram([0, 1], cudaStreams);        // Borrowed streams, one per device
using Executor striped = Executor.ForNvme(paths: ["/mnt/nvme0", "/mnt/nvme1"]);
```

One call holds an executor at a time, while handles stay freely concurrent, so a caller wanting genuine concurrency gives each thread its own executor.

### Receivers & Deferred Calls

The receiver chooses where a verb runs, and the verb stays the same.
Called on the index, a verb runs on the caller's own thread, single-threaded on RAM and on the handle's device and default stream on VRAM.
On `index.On(executor)` it blocks on that executor, refused while another call holds it.
On `index.Deferred(executor)` it submits there and answers a `Deferred<TResult>` at once.

```csharp
Matches local = index.Search(queries, wanted: 10, arena);                 // The caller's thread
Matches pooled = index.On(pool).Search(queries, wanted: 10, arena);       // Blocking, on the pool
Matches awaited = await index.Deferred(pool).Search(queries, 10, arena);  // Or: .Wait() in place of await
```

A `Deferred<TResult>` owns its outcome and the pins on every input it lends the library until the call is final, and borrows its index and arena exactly as a blocking call does, so `Wait()` answers the same view a blocking call would, over the same arena.
`Status` reads `Status.Deferred` until then, `Wait()` blocks and answers the result or raises the failure, and `await` runs that wait on the thread pool.
Verbs that produce nothing answer a plain `Deferred`, as `Task` stands beside `Task<TResult>`.

```csharp
using Deferred<Matches> call = index.Deferred(pool).Search(queries, wanted: 10, arena);
if (call.Status == Status.Deferred)
{
    // other work
}
Matches matches = await call;                                       // Or: call.Wait()
```

Waiting again answers the same result or raises the same failure.
Disposing a call nobody waited for waits for it, discards what it produced, and lets its arena serve the next call.
One left unfinished and unreachable keeps its outputs and pins alive until a collection finds it final, rather than freeing memory the library still writes.
Disposing an index or an arena that a deferred call names waits for that call first.
One call holds an executor at a time, so a second call finding it held finishes at once with `Status.Contended`, and nothing queues.
A deferred call on a caller-exclusive pool runs on the pool's thread 0, so polling alone finishes it, and its progress handler and predicate run on the pool's threads; a single thread or a VRAM executor runs it at submission.
Calls depending on each other are ordered by waiting on the first before submitting the second.

`using Cloud.Unum.USearch;`

## Deferred

A submitted call, which owns its outcome and the pins on its inputs until the call is final, and borrows its index and arena as a blocking call does; the verbs that produce nothing answer this, the rest a Deferred<TResult>.

```csharp
class Deferred
```

Status polls without blocking, Wait blocks until the call is final and raises its failure, and `await` runs that wait on the thread pool. Disposing one nobody waited for waits for it, then discards what it produced and lets its arena serve the next call.

Every wait after the first answers the same result or raises the same failure, and Status keeps reading the final status. One left unfinished and unreachable is released by the first collection that finds it final, rather than freeing memory the library still reads and writes.

## Wait

Blocks until the call is final, then raises its failure. Calls `usearch_outcome_wait`.

```csharp
void Wait();
```

## GetAwaiter

Waits on the thread pool, so `await` suspends the caller rather than blocking it.

```csharp
TaskAwaiter GetAwaiter();
```

Binding-only.

## Dispose

Waits for an unfinished call and discards what it produced; a call already waited for is left as it is.

```csharp
void Dispose();
```

Calls `usearch_outcome_wait`.

## Executor

The workers every fanned-out verb runs on, shared across indexes.

```csharp
class Executor
```

An executor owns host threads or device streams; an index owns entries. Keeping them apart is what lets one pool serve several indexes, and what makes the cost of spawning visible at the line that spawns rather than hidden in a constructor.

One factory per C constructor, each taking only what its own hardware has: host workers and memory domains for RAM, a borrowed ForkUnion pool for OnPool, one submission ring apiece per device path for NVMe, and device ordinals with optional borrowed streams for VRAM, where a single host thread drives one stream per device and there is no thread count to name. The kind must match the residency of every handle the executor drives, and a mismatch fails the call with Status.Device.

A verb runs on an executor when its receiver names one, as `index.On(pool)` and `index.Deferred(pool)` do, and on the caller's own thread when called on the index itself: single-threaded on RAM, on the handle's device and default stream on VRAM. Calls on one executor run in submission order, while handles stay freely concurrent - it is the executor that orders, never the index.

```
using Executor pool = Executor.ForRam(threads: 8);
using DenseIndex index = DenseIndex.InitRam(DenseOptions.Default with { Dimensions = 3 });
index.On(pool).Insert(keys, RowsView.RowsOf(vector, 3));
```

## ForRam

Spawns host workers for RAM-resident indexes, interleaved across the compute domains local to the named memory domains - the very IDs the indexes were initialized with.

```csharp
Executor ForRam(
    ulong threads = 0,
    ReadOnlySpan<int> memoryDomains = default,
    ulong deferredLimit = 0,
    CPUClass? cpuClass = null);
```

Calls `usearch_executor_for_ram`.

- `threads`: The worker count; zero takes 7/8 of the cores those domains carry, since full occupancy starves the ordered publication path.
- `memoryDomains`: NUMA node IDs to place shards on; empty derives every node the process may allocate on.
- `deferredLimit`: The deferred calls tracked at once; zero takes a default.
- `cpuClass`: The class whose waiters and atomics the threads use; null derives the CPU's own.

## OnPool

Wraps a ForkUnion pool another library already runs, so one process keeps one set of threads while each library keeps its own scratch.

```csharp
Executor OnPool(
    IntPtr pool,
    ReadOnlySpan<int> memoryDomains = default,
    ulong deferredLimit = 0,
    CPUClass? cpuClass = null);
```

Calls `usearch_executor_on_pool`.

- `pool`: The borrowed `fu_pool_t`, which must outlive the executor and keeps its lender's mood.
- `memoryDomains`: NUMA node IDs of the indexes it will drive; empty derives.
- `deferredLimit`: The deferred calls tracked at once; zero takes a default.
- `cpuClass`: The class whose waiters and atomics the threads use; null derives the CPU's own.

## ForNvme

Spawns host workers for NVMe-resident indexes, one submission ring apiece, across the compute domains local to the devices the paths name.

```csharp
Executor ForNvme(
    ulong threads = 0,
    ReadOnlySpan<string> paths = default,
    ulong deferredLimit = 0,
    CPUClass? cpuClass = null);
```

Calls `usearch_executor_for_nvme`.

- `threads`: The ring count; zero derives from those devices' queue capabilities.
- `paths`: Devices or directories to place shards on; empty leaves each shard where its manifest points.
- `deferredLimit`: The deferred calls tracked at once; zero takes a default.
- `cpuClass`: The class whose waiters and atomics the threads use; null derives the CPU's own.

## ForVram

Opens one submission stream on every named device, or borrows the caller's, all of them driven by the one host thread that calls the verbs - which is why this factory takes no thread count.

```csharp
Executor ForVram(
    ReadOnlySpan<int> devices = default,
    ReadOnlySpan<IntPtr> streams = default,
    ulong scratchLimit = 0,
    ulong deferredLimit = 0,
    GPUClass? gpuClass = null);
```

Calls `usearch_executor_for_vram`.

- `devices`: CUDA device ordinals to place shards on; empty derives one free device.
- `streams`: Borrowed CUDA streams, one per device in that order; empty opens its own.
- `scratchLimit`: The ceiling on scratch bytes per device; zero lets scratch grow as geometry asks.
- `deferredLimit`: The deferred calls tracked at once; zero takes a default.
- `gpuClass`: A class the devices must run, refused with Status.Unsupported otherwise; null takes the devices' own.

## Drain

Waits for every call submitted to this executor, then sets the mood it adopts whenever it next goes idle.

```csharp
void Drain(Mood mood = Mood.Parked);
```

Calls `usearch_executor_drain`.

- `mood`: What the executor does with its workers once idle; the last drain wins.

## Dispose

Drains every thread or stream, releases the scratch it owns, and frees the executor.

```csharp
void Dispose();
```

Freeing cannot fail, and a freed executor must not be used. Calls `usearch_executor_free`.

## ICall

One verb's call: what it lends the library, and what it builds once final.

```csharp
interface ICall
```

A verb is written once as such a struct, and the receiver alone decides whether it blocks or defers.

## Submit

Fixes what the call lends, pinning it past the C verb only when deferred, and leases its handles for the C verb alone, then calls it with its outputs written to _outputs_ .

```csharp
void Submit(CallOutputs *outputs, Completion completion);
```

Throws only before the C verb is called.

## Release

Settles what the call handed over - donors it consumed - then unpins what it lent, once the call is final.

```csharp
void Release(CallOutputs *outputs);
```

## Finish

Raises the failure of a final call, or builds what it produced.

```csharp
void Finish(CallOutputs *outputs);
```

