rust - 什么是 futures::future::lazy?

标签 rust future rust-tokio

Tokio documentation我们有这个片段:

extern crate tokio;
extern crate futures;

use futures::future::lazy;

tokio::run(lazy(|| {
    for i in 0..4 {
        tokio::spawn(lazy(move || {
            println!("Hello from task {}", i);
            Ok(())
        }));
    }

    Ok(())
}));

对此的解释是:

The lazy function runs the closure the first time the future is polled. It is used here to ensure that tokio::spawn is called from a task. Without lazy, tokio::spawn would be called from outside the context of a task, which results in an error.

尽管我对 Tokio 有一些了解,但我不确定我是否准确理解了这一点。看起来这两个 lazy 的作用略有不同,而且这个解释只适用于第一个。第二次调用 lazy(在 for 循环内)不就是为了将闭包转换为 future 吗?

最佳答案

lazy 的目的包含在 documentation for lazy 中:

Creates a new future which will eventually be the same as the one created by the closure provided.

The provided closure is only run once the future has a callback scheduled on it, otherwise the callback never runs. Once run, however, this future is the same as the one the closure creates.

就像普通闭包一样,它用于防止代码被急切求值。用同步术语来说,就是调用函数和调用函数返回的闭包之间的区别:

fn sync() -> impl FnOnce() {
    println!("This is run when the function is called");
    
    || println!("This is run when the return value is called")
}

fn main() {
    let a = sync();
    println!("Called the function");
    a();
}

和 future 0.1 的并行:

use futures::{future, Future}; // 0.1.27

fn not_sync() -> impl Future<Item = (), Error = ()> {
    println!("This is run when the function is called");

    future::lazy(|| {
        println!("This is run when the return value is called");
        Ok(())
    })
}

fn main() {
    let a = not_sync();
    println!("Called the function");
    a.wait().unwrap();
}

使用 async/await 语法,应该不再需要这个函数了:

#![feature(async_await)] // 1.37.0-nightly (2019-06-05)

use futures::executor; // 0.3.0-alpha.16
use std::future::Future;

fn not_sync() -> impl Future<Output = ()> {
    println!("This is run when the function is called");

    async {
        println!("This is run when the return value is called");
    }
}

fn main() {
    let a = not_sync();
    println!("Called the function");
    executor::block_on(a);
}

如您所见,Tokio 的示例使用 lazy 来:

  • 确保闭包中的代码仅从执行器内部运行。
  • 确保关闭作为 future 运行

我认为 lazy 的这两个方面实际上是一样的。

另见:

关于rust - 什么是 futures::future::lazy?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56544469/

相关文章:

rust - 如何在 rust/tokio 的 TCP 客户端绑定(bind)()?

rust - 无法使用 std::process::Command - 没有这样的文件或目录

c++ - 与 std::future::unwrap 竞争异常传播

concurrency - Erlang 中的 future 和 promise

Scala, ZIO - 将 Future 转换为 ZIO 或 ZIO 转换为 Future。可能吗?

rust - `RwLockWriteGuard<' _, T>` 没有实现 T 实现的特征

rust - 如何向 tokio-io 添加特殊的 NotReady 逻辑?

rust - "borrowed value does not live long enough"好像怪错了

rust - 当某些项目需要替换时,实现 `IntoIterator` 的惯用方法是什么?

compiler-errors - 奇怪地重复出现的通用特征模式 : overflow evaluating the requirement