queue.rs (2649B)
1 use spinoff::{spinners, Spinner}; 2 use std::time::Duration; 3 use tch::Tensor; 4 use tokio::{ 5 sync::{ 6 mpsc::{channel, Receiver, Sender}, 7 oneshot::{ 8 channel as oneshot_channel, Receiver as OneshotReceiver, Sender as OneshotSender, 9 }, 10 }, 11 time::{timeout, Instant}, 12 }; 13 14 use crate::model::{Label, Model}; 15 16 type Job = (Tensor, OneshotSender<Label>); 17 18 pub struct Queue { 19 sender: Sender<Job>, 20 } 21 22 impl Queue { 23 pub fn new(batch_size: usize) -> (Self, Receiver<Job>) { 24 let (sender, receiver) = channel(batch_size * 2); 25 (Self { sender }, receiver) 26 } 27 28 pub async fn add(&self, tensor: Tensor) -> anyhow::Result<OneshotReceiver<Label>> { 29 let (result_tx, result_rx) = oneshot_channel(); 30 self.sender 31 .send((tensor, result_tx)) 32 .await 33 .map_err(|_| anyhow::anyhow!("Queue is closed, cannot accept new jobs"))?; 34 Ok(result_rx) 35 } 36 } 37 38 pub async fn run( 39 mut receiver: Receiver<Job>, 40 model: Model, 41 batch_size: usize, 42 batch_timeout: Duration, 43 ) { 44 let mut spinner = Spinner::new(spinners::Line, "Waiting for jobs", None); 45 46 loop { 47 let (first_tensor, first_tx) = match receiver.recv().await { 48 Some(job) => job, 49 None => break, 50 }; 51 52 let mut tensors = vec![first_tensor]; 53 let mut transmitters = vec![first_tx]; 54 55 let start = Instant::now(); 56 while tensors.len() < batch_size { 57 let elapsed = start.elapsed(); 58 if elapsed >= batch_timeout { 59 break; 60 } 61 62 match timeout(batch_timeout - elapsed, receiver.recv()).await { 63 Ok(Some((tensor, tx))) => { 64 tensors.push(tensor); 65 transmitters.push(tx); 66 } 67 _ => break, 68 } 69 } 70 71 spinner.update_text(format!( 72 "Executing {} job(s) with {} still queued", 73 tensors.len(), 74 receiver.len() 75 )); 76 77 if let Err(e) = process_batch(&model, tensors, transmitters).await { 78 eprintln!("Batch error: {}", e); 79 } 80 81 spinner.update_text("Waiting for jobs"); 82 } 83 } 84 85 async fn process_batch( 86 model: &Model, 87 tensors: Vec<Tensor>, 88 transmitters: Vec<OneshotSender<Label>>, 89 ) -> anyhow::Result<()> { 90 let stacked = Tensor::f_stack(&tensors, 0)?; 91 92 let labels = model.label(&stacked)?; 93 94 for (label, tx) in labels.iter().zip(transmitters) { 95 if tx.send(*label).is_err() { 96 eprintln!("Receiver dropped for a job, result lost"); 97 } 98 } 99 100 Ok(()) 101 }