Skip to main content

Crate amate

Crate amate 

Source
Expand description

Dynamic batching on worker threads, with no dependencies.

Named after Amaterasu, the sun goddess of Japanese myth, who gathers scattered light and sends it out at once, as amate gathers waiting requests into one batch.

Items queue to a few worker threads, each running one batch at a time. While some worker is idle, every item gets a batch of its own, started at once. Once all workers are busy, the queue fills, and the next worker to finish takes everything queued, up to Config::max_batch by weight, as one batch. If the queue runs dry before the batch is full, the worker waits for more, but never longer than the Batching::window after the first item was queued: a server waits only while an announced item is still on its way in (its body is being received or decoded, see Engine::arrival), a batch that sums over time waits out its window (Config::waits_unannounced). Items nobody wants any more (their client gave up) are skipped, and a batch that panics loses only its own items, where panics unwind: with panic = "abort" the process stops.

What a batch is made of, how heavy each item is, how long the window is and what to do with the batch are the Batching’s: the engine knows nothing about models or replies. It is the algorithm behind furnace’s dynamic batching.

use std::sync::mpsc;
use std::time::Duration;
use amate::{Batching, Config, Engine, Queued};

/// Sums the numbers of each batch and sends the totals on
struct Sum(mpsc::Sender<u64>);

impl Batching for Sum {
    type Item = u64;

    fn weight(&self, _: &u64) -> usize {
        1
    }

    fn window(&self) -> Duration {
        Duration::from_millis(2)
    }

    fn run(&self, batch: Vec<Queued<u64>>) {
        let _ = self.0.send(batch.iter().map(|queued| queued.item).sum());
    }
}

let (totals, received) = mpsc::channel();
let config = Config { max_batch: 8, workers: 2, capacity: Some(1024), waits_unannounced: false };
let engine = Engine::start(Sum(totals), config, |i| format!("sum-{i}"));
for n in 1..=10 {
    engine.submit(None, n).unwrap();
}
// The workers run what is queued, then stop, and `Sum` with them
drop(engine);
assert_eq!(received.iter().sum::<u64>(), 55);

Structs§

Arrival
See Engine::arrival
Config
Engine
Handle to the workers; they stop when it is dropped
Queued
An item and when it was queued

Traits§

Batching
What a batch is made of and what to do with one