Available on crate feature
async only.Expand description
Process several streams concurrently with ProcessorAsync on an async runtime.
In addition to the instructions at examples,
you have to enable the async feature:
cargo add aic-sdk --features download-lib,download-model,asyncAnd you have to add two more crates:
cargo add futures
cargo add tokio --features macros,rt-multi-threadsrc/main.rs:
// Demonstrates that multiple `ProcessorAsync` instances genuinely run in
// parallel when awaited concurrently.
//
// Each processor records its own wall-clock processing time. If they ran
// sequentially, the total elapsed time would be roughly `N × per-processor time`.
// When running in parallel the total time is close to the slowest
// single processor, which is what we verify and print.
use aic_sdk::{Model, ProcessorAsync, ProcessorConfig};
use std::time::Instant;
const MODEL: &str = "quail-vf-2.2-l-16khz";
const NUM_PROCESSORS: usize = 4;
// Number of process calls per processor – enough to make timing visible.
const ITERATIONS: usize = 50;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("ai-coustics SDK version: {}", aic_sdk::get_sdk_version());
let license = std::env::var("AIC_SDK_LICENSE").expect("AIC_SDK_LICENSE not set");
let model_path = Model::download(MODEL, "target")?;
let model = Model::from_file(&model_path)?;
println!("Model loaded from {}", model_path.display());
let config = ProcessorConfig::optimal(&model);
println!(
"Config: {} Hz, block size {}\n",
config.sample_rate, config.block_size
);
// Build all processors up front
let processors = futures::future::try_join_all((0..NUM_PROCESSORS).map(|_| async {
ProcessorAsync::new(&model, &license)?
.with_config(&config)
.await
}))
.await?;
println!(
"Running {} processors × {} iterations each",
NUM_PROCESSORS, ITERATIONS
);
let buf_len = config.block_size;
// Sequential baseline
let sequential_start = Instant::now();
for p in &processors {
let mut audio = vec![0.0f32; buf_len];
for _ in 0..ITERATIONS {
audio = p.process(audio).await?;
}
}
let sequential_elapsed = sequential_start.elapsed();
println!(
"Sequential total: {:>8.1} ms",
sequential_elapsed.as_secs_f64() * 1000.0
);
// Parallel run
let parallel_start = Instant::now();
let tasks: Vec<_> = processors
.iter()
.map(|p| {
let config = config.clone();
async move {
let mut audio = vec![0.0f32; config.block_size];
let t0 = Instant::now();
for _ in 0..ITERATIONS {
audio = p.process(audio).await?;
}
Ok::<_, aic_sdk::AicError>(t0.elapsed())
}
})
.collect();
let results = futures::future::try_join_all(tasks).await?;
let parallel_elapsed = parallel_start.elapsed();
for (id, elapsed) in results.iter().enumerate() {
println!(
" Processor {:>2} finished in {:>8.1} ms",
id + 1,
elapsed.as_secs_f64() * 1000.0,
);
}
let max_individual = results.iter().max().copied().unwrap_or_default();
println!(
"\nParallel total: {:>8.1} ms",
parallel_elapsed.as_secs_f64() * 1000.0
);
println!(
"Slowest processor: {:>8.1} ms",
max_individual.as_secs_f64() * 1000.0,
);
let speedup = sequential_elapsed.as_secs_f64() / parallel_elapsed.as_secs_f64();
println!(
"\nSpeedup vs sequential: {:.2}x (ideal ≈ {}x)",
speedup, NUM_PROCESSORS
);
println!(
"{}",
if speedup > 1.5 {
"Parallel execution confirmed."
} else {
"Warning: low speedup – your system may not have enough CPU cores, or the model may be too small for parallelism to be visible."
}
);
Ok(())
}