Tokio术语

Tokio术语

来自:https://tokio.rs/tokio/glossary

异步(Asynchronous)

在Rust的上下文中,异步代码指的是使用async/await语言特性的代码,它允许许多任务在几个线程(甚至是一个单线程)上并发运行。

并发(Concurrency)和并行(Parallelism)

并发和并行是两个相关的概念,在谈论同时执行多个任务时都会用到。如果某件事情是平行发生的,那么它也是并发发生的,但反过来就不是这样了。在两个任务之间交替进行,但实际上从未同时进行两个任务,这就是并发,但不是并行。

未来(Future)

Future是一个存储某些操作的当前状态的值。future也有一个poll方法,它使操作继续进行,直到它需要等待某些东西,比如网络连接。对poll方法的调用应该很快返回。

Future通常是通过在一个异步块中使用.await来组合多个Future来创建的。

执行器(Executor)/调度器(scheduler)

执行器或调度器是通过重复调用poll方法来执行future的东西。标准库中没有执行器,所以你需要一个外部库来实现,而使用最广泛的执行器是由Tokio运行时提供。

执行器能够在几个线程上并发地运行大量的 future。它通过在等待时交换当前运行的任务来做到这一点。如果代码花了很长时间都没有到达 .await,这就被称为 “阻塞线程” 或 “not yielding back to the executor”,这将阻止其他任务的运行。

运行时(Runtime)

运行时是一个库,它包含执行器以及与该执行器集成的各种实用工具,如定时实用工具和IO。运行时和执行器这两个词有时可以互换使用。标准库没有运行时,所以你需要一个外部库来实现,最广泛使用的运行时是 Tokio 运行时。

Runtime这个词也用在其他场合,例如,“Rust没有运行时 “这句话有时被用来表示Rust不执行垃圾收集或即时(just-in-time,JIT)编译。

任务(Task)

任务是在Tokio运行时上运行的操作,由 tokio::spawnRuntime::block_on 函数创建。通过组合创建期货的工具,如 .awaitjoin! 并不创建新的任务,每个组合的部分被说成是 “在同一个任务中”。

多个任务是需要并行的,但使用 join! 等工具可以在一个任务上并发地做多件事情。

spawn

spawn 是指使用 tokio::spawn 函数来创建一个新的任务。它也可以指用std::thread::spoon创建新的线程。

异步块(Async block)

异步块是创建一个运行一些代码的future的简单方法。比如说:

let world = async {
    println!(" world!");
};
let my_future = async {
    print!("Hello ");
    world.await;
};

上面的代码创建了一个名为 my_future 的future,如果执行它,就会打印出 Hello world!。 它是通过首先打印 hello,然后运行 world future来实现的。请注意,上面的代码不会自己打印任何东西–你必须在任何事情发生之前实际执行my_future,要么直接生成(spawn)它,要么在你生成(spawn)的东西中等待它。

异步函数(Async function)

与异步块类似,异步函数是一种创建函数的简单方法,其主体成为一个future。所有的异步函数都可以被改写成返回一个future的普通函数。

async fn do_stuff(i: i32) -> String {
    // do stuff
    format!("The integer is {}.", i)
}
use std::future::Future;

// the async function above is the same as this:
fn do_stuff(i: i32) -> impl Future<Output = String> {
    async move {
        // do stuff
        format!("The integer is {}.", i)
    }
}

这使用 impl Trait 语法来返回一个 future,因为 Future 是一个 trait。请注意,由于由异步块创建的 future 在执行之前不会做任何事情,所以调用异步函数在其返回的 future 被执行之前不会做任何事情(忽略它将触发一个警告)。

让出(Yielding)

在异步Rust的背景下,Yielding是允许执行者在单个线程上执行许多future的原因。每当一个future让出时,执行者能够将该future与其他future交换,通过反复交换当前任务,执行者可以并发地执行大量的任务。future只能在 .await 时让出,所以在 .await 之间花很长时间的future可以阻止其他任务的运行。

具体来说,future只要从 poll 方法中返回就会让出。

阻塞(Blocking)

“阻塞(blocking)“这个词有两种不同的用法: 阻塞的第一个含义是简单地等待某事完成,而阻塞的另一个含义是当一个 future 花很长的时间而不让出。为了明确起见,你可以用 “阻塞线程” 这个短语来表示第二种含义。

Tokio的文档总是使用 “阻塞” 的第二种含义。

要在Tokio中运行阻塞代码,请参见Tokio API参考中的 CPU绑定任务和阻塞代码 部分。

流(Stream)

StreamIterator 的异步版本,它提供了一个数值流。它通常与 while let 循环一起使用,就像这样:

use tokio_stream::StreamExt; // for next()

while let Some(item) = stream.next().await {
    // do something
}

流这个词有时被混乱地用来指代 AsyncReadAsyncWrite 特性。

Tokio的流工具目前是由 tokio-stream crate提供的。一旦Stream特性在std中稳定下来,Stream工具将被移到 tokio crate中。

通道(Channel)

通道是一种工具,允许代码的一个部分向其他部分发送消息。Tokio提供了许多通道,每个通道都有不同的用途:

  • mpsc:多生产者、单消费者通道。可以发送许多值。
  • oneshot:单生产者,单消费者通道。可以发送一个单一的值。
  • broadcast:多生产者,多消费者。可以发送许多值。每个接收者看到每个值。
  • watch:单生产者,多消费者。可以发送许多值,但不保留历史。接收者只看到最新的值。

如果你需要一个多生产者多消费者的通道,每个消息只有一个消费者看到,你可以使用 async-channel crate。

还有一些通道是在异步Rust之外使用的,比如 std::sync::mpsccrossbeam::channel。这些通道通过阻塞线程来等待消息,这在异步代码中是不允许的。

背压(Backpressure)

背压是一种设计对高负荷反应良好的应用程序的模式。例如,mpsc 通道有有界的和无界的两种形式。通过使用有界通道,如果接收方不能跟上消息的数量,接收方可以对发送方施加 “背压”,这就避免了随着通道上的消息越来越多,内存使用量无限制地增长。

Actor

一种设计应用程序的模式。Actor是指一个独立生成的任务,它代表应用程序的其他部分管理一些资源,使用通道与应用程序的其他部分进行通信。