rust学习(tokio future分析)

自己编写一个impl future来看一下Tokio的是如何实现的。

第一步:

代码:

struct TExecuteTask {
    count:u32
}

impl Future for TExecuteTask {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            println!("future require");
            if self.count == 2 {
                return Ready(());
            }

            unsafe {
                self.get_unchecked_mut().count += 1;
            }
            Pending
    }
}

pub fn test1() {
    let v = TExecuteTask{count:0};
    let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
    println!("test trace1");
    rt.block_on(v);
    println!("test trace2");
}

运行结果:

貌似调用block_on之后会回调一次future的poll,如果这个时候还没有计算出结果,那就直接卡死了,所以需要找个地方能唤醒。

第二步:

原来代码上添加上wake

impl Future for TExecuteTask {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            println!("future require");
            let mut v = self.core.lock().unwrap();
            v.waker = Some(cx.waker().clone());
            Pending
    }
}

pub fn test1() {
    let waker: Arc<Mutex<TExecuteTaskCore>> = Arc::new(Mutex::new(TExecuteTaskCore {
        waker:None
    }));

    let task: TExecuteTask = TExecuteTask {
        core:waker.clone()
    };
    
    let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
    
    let closure1 = waker.clone();
    thread::spawn(move|| {
        thread::sleep(Duration::from_secs(1));
        let mut core: std::sync::MutexGuard<'_, TExecuteTaskCore> = closure1.lock().unwrap();
        if let Some(waker) = core.waker.take() {
            println!("detect future is ready, wakeup the future task to executor.");
            waker.wake()    // wakeup the future task to executor.
        }
    });
    println!("test trace1");
    rt.block_on(task);
    println!("test trace2");
}

关键是在poll返回pending的时候,获取waker。然后等计算完成后再wake一下哈哈。

然后结果呢:

还是卡住了。。。这个是为啥呢?原来是我poll的代码有问题,无论如何处理都是返回pending..

所以从目前的试验来看有如下结论:

1.当调用block_on的时候,会直接调用一次future的poll确认是否运算结束。

2.当调用waker.wake的时候貌似还会调用一次poll确认是否运算结束。

所以我们现在要加一个标志位来表示运算结束,这样block_on应该就能正常走下去了吧。

第三步:

impl Future for TExecuteTask {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
            println!("future require");
            let mut v = self.core.lock().unwrap();
            if v.complete == true {
                return Ready(())
            }

            v.waker = Some(cx.waker().clone());
            Pending
    }
}

pub fn test1() {
    let waker: Arc<Mutex<TExecuteTaskCore>> = Arc::new(Mutex::new(TExecuteTaskCore {
        waker:None,
        complete:false
    }));

    let task: TExecuteTask = TExecuteTask {
        core:waker.clone()
    };
    
    let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap();
    
    let closure1 = waker.clone();
    thread::spawn(move|| {
        thread::sleep(Duration::from_secs(1));
        let mut core: std::sync::MutexGuard<'_, TExecuteTaskCore> = closure1.lock().unwrap();
        if let Some(waker) = core.waker.take() {
            println!("detect future is ready, wakeup the future task to executor.");
            core.complete = true;
            waker.wake()    // wakeup the future task to executor.
        }
    });
    println!("test trace1");
    rt.block_on(task);
    println!("test trace2");
}

添加了一个complete标志运算是否结束。

运算完成后,complete赋值为true,再尝试wake一下等待线程(协程?)

poll中也添加了complete判断,如果为true的话,直接返回Ready,然后我们看一下运行结果:

运行结束~~。哈哈。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rust的std::future是一种表示异步操作结果的类型,它可以在不阻塞线程的情况下等待异步操作完成,并返回结果。下面是使用std::future的基本步骤: 1. 导入future模块:在代码文件的开头添加“use std::future::Future;”语句。 2. 创建异步任务:创建一个异步任务,例如使用async语法创建一个异步函数,返回值类型为Future。 3. 等待异步任务:使用await关键字等待异步任务完成,并获取结果。 下面是一个简单的例子: ```rust use std::future::Future; async fn async_task() -> i32 { 1 + 2 } fn main() { let future = async_task(); // 创建异步任务 let result = futures::executor::block_on(future); // 等待异步任务完成 println!("Result: {}", result); // 打印结果 } ``` 在这个例子中,我们创建了一个异步函数async_task(),返回一个Future,表示一个异步操作。在main函数中,我们调用async_task()创建一个异步任务,并使用futures::executor::block_on()函数等待异步任务完成,并获取结果。最后打印结果。 需要注意的是,使用block_on函数会阻塞当前线程,直到异步任务完成。为了避免阻塞线程,可以使用异步运行时(async runtime)来执行异步任务。Rust提供了多个异步运行时库,例如tokio、async-std、smol等。下面是使用tokio库的例子: ```rust use std::future::Future; use tokio::runtime::Runtime; async fn async_task() -> i32 { 1 + 2 } fn main() { let future = async_task(); // 创建异步任务 let mut rt = Runtime::new().unwrap(); // 创建异步运行时 let result = rt.block_on(future); // 在异步运行时中执行异步任务 println!("Result: {}", result); // 打印结果 } ``` 在这个例子中,我们使用tokio库创建了一个异步运行时,并使用run_until_complete()函数在异步运行时中执行异步任务。这样可以避免阻塞线程,提高程序性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值