wd_pool 0.1.0

A pool crate for rust
Documentation
use std::f32::consts::E;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
use std::time::Duration;
use crate::{TaskPool};
use async_channel::{Sender,Receiver};


pub struct TaskPoolChannel {
    status: Arc<AtomicBool>,
    cache_len:Option<usize>,
    idle:i32,
    max:i32,
    idle_sleep_time:Duration,
    active:Arc<AtomicI32>,
    sender:Sender<Pin<Box<dyn Future<Output=()> + Send > >>,
    receiver:Receiver<Pin<Box<dyn Future<Output=()> + Send >>>
}

impl Default for TaskPoolChannel {
    fn default() -> Self {
        let (sender,receiver) = async_channel::unbounded();
        Self{
            status: Arc::new(AtomicBool::new(true)),
            cache_len:None,
            idle: 8, //计算cpu的个数
            idle_sleep_time: Duration::from_secs(1),
            max: i32::MAX,
            active: Arc::new(Default::default()),
            sender,receiver
        }
    }
}

impl TaskPoolChannel{
    pub fn set_cache_len(mut self,len:usize)->Self{
        self.cache_len = Some(len);self
    }
    pub fn set_idle(mut self,idle:i32)->Self{
        self.idle = idle;self
    }
    pub fn set_max_parallel(mut self,max:i32)->Self{
        self.max = max;self
    }
    pub fn set_idle_sleep_time(mut self,idle_sleep_time:Duration)->Self{
        self.idle_sleep_time = idle_sleep_time;self
    }
    pub fn build(mut self) -> impl TaskPool<Out=()> {
        self.init();
        self
    }
}

impl TaskPoolChannel {
    fn init(&mut self){
        if let Some(len) = self.cache_len{
            let (sender,receiver) = async_channel::bounded(len);
            self.sender = sender;
            self.receiver = receiver;
        }
        for _ in 0..self.idle {
            Self::generate_worker(self.idle,self.active.clone(),self.receiver.clone());
        }
    }
    fn generate_worker(idle:i32,active:Arc<AtomicI32>,receiver:Receiver<Pin<Box<dyn Future<Output=()> + Send >>>){
        active.fetch_add(1,Ordering::Relaxed);
        tokio::spawn(async move{
            while !receiver.is_closed() {
                let task = match receiver.try_recv() {
                    Ok(o)=>o,
                    Err(_)=>{
                        if active.load(Ordering::Relaxed) > idle {
                            break
                        }
                        tokio::time::sleep(Duration::from_millis(100)).await;
                        continue
                    }
                };
                task.await;
            }
            active.fetch_sub(1,Ordering::Relaxed);
        });
    }
}


#[async_trait::async_trait]
impl TaskPool for TaskPoolChannel {
    type Out = ();

    async fn push<F: Future<Output=()> + Send + 'static>(&self, task: F)  ->anyhow::Result<Self::Out> {
        if !self.status.load(Ordering::Relaxed) {
            return Err(anyhow::anyhow!("TaskPoolChannel is not normal"))
        }
        if !self.sender.is_closed() {
            let _ = self.sender.send(Box::pin(task)).await;
        }
        Ok(())
    }

    async fn close(&self, timeout: Duration) -> anyhow::Result<()> {
        self.sender.close();
        let active = self.active.clone();
        tokio::time::timeout(timeout,async move{
            while active.load(Ordering::Relaxed) > 0 {
                tokio::time::sleep(Duration::from_secs(1)).await;
            }
        }).await?;Ok(())
    }
}