跳到主要内容

Module task

搜索

Module task 

源代码
展开描述

异步绿色线程。

§What are Tasks?

任务是一个轻量级、非阻塞的执行单元。任务类似于 OS 线程,但它们不是由 OS 调度器管理,而是由 Tokio 运行时管理。这种通用模式的另一个名称是绿色线程。如果你熟悉 Go 的 goroutineKotlin 的协程Erlang 的进程,则可以将 Tokio 的任务视为类似的东西。

关于任务的关键点包括:

  • 任务是轻量级的。由于任务是由 Tokio 运行时而非操作系统调度的,因此创建新任务或在任务之间切换不需要上下文切换,开销相当低。创建、运行和销毁大量任务是相当廉价的,尤其是与 OS 线程相比。

  • 任务被协作式调度。大多数操作系统实现抢占式多任务。这是一种调度技术,操作系统允许每个线程运行一段时间,然后抢占它,临时暂停该线程并切换到另一个线程。而任务实现的是协作式多任务。在协作式多任务中,任务被允许一直运行,直至它让步,向 Tokio 运行时的调度器表明它当前无法继续执行。当任务让步时,Tokio 运行时将切换执行下一个任务。

  • 任务是非阻塞的。通常,当 OS 线程执行 I/O 或必须与另一个线程同步时,它会阻塞,允许 OS 调度另一个线程。当任务无法继续执行时,它必须让步,从而允许 Tokio 运行时调度另一个任务。任务通常不应执行可能阻塞线程的系统调用或其他操作,因为这会阻止在同一线程上运行的其他任务的执行。相反,本模块提供了在异步上下文中运行阻塞操作的 API。

§Working with Tasks

本模块提供以下用于处理任务的 API:

§Spawning

本模块中最重要的函数可能是 task::spawn。可以将此函数视为标准库 thread::spawn 的异步等价物。它接受一个 async 块或其他 future,并创建一个新任务以并发运行该工作:

use tokio::task;

task::spawn(async {
    // perform some work here...
});

std::thread::spawn 一样,task::spawn 返回一个 JoinHandle 结构体。JoinHandle 本身是一个 future,可用于等待已生成任务的输出。例如:

use tokio::task;

let join = task::spawn(async {
    // ...
    "hello world!"
});

// ...

// Await the result of the spawned task.
let result = join.await?;
assert_eq!(result, "hello world!");

同样,与 std::threadJoinHandle 类型 一样,如果已生成的任务发生 panic,则等待其 JoinHandle 将返回 JoinError。例如:

use tokio::task;

let join = task::spawn(async {
    panic!("something bad happened!")
});

// The returned result indicates that the task failed.
assert!(join.await.is_err());

启用 “rt” 特性标志时,存在 spawnJoinHandleJoinError

§Cancellation

可以使用 JoinHandle::abortAbortHandle::abort 方法取消已生成的任务。当调用这些方法之一时,任务被发出信号,以在下次于 .await 点让步时关闭。如果任务已空闲,则它将在不再次运行的情况下尽快关闭。此外,关闭 Tokio 运行时(例如通过从 #[tokio::main] 返回)会立即取消其上的所有任务。

当任务关闭时,它将在其所让步的 .await 处停止运行。所有局部变量都通过运行其析构函数被销毁。一旦关闭完成,等待 JoinHandle 将失败并返回已取消错误

请注意,中止任务并不能保证它会以已取消错误失败,因为它可能先正常完成。例如,如果任务在 abort 调用与任务结束之间的任何时候都没有向运行时让步,那么 JoinHandle 将改为报告任务正常退出。

请注意,使用 spawn_blocking 派生的任务无法被中止,因为它们不是异步的。如果对 spawn_blocking 任务调用 abort则不会产生任何效果,任务将继续正常运行。例外情况是任务尚未开始运行;此时调用 abort 可能会阻止任务启动。

请注意,对 JoinHandle::abort 的调用只是将任务调度为取消,并将在取消完成之前返回。要等待取消完成,请通过等待 JoinHandle 等待任务完成。同样,JoinHandle::is_finished 方法在取消完成之前不会返回 true

多次调用 JoinHandle::abort 与调用一次的效果相同。

Tokio 还提供 AbortHandle,它类似于 JoinHandle,但不提供等待任务完成的机制。每个任务只能有一个 JoinHandle,但可以有多个 AbortHandle

§Blocking and Yielding

正如我们上面讨论的,在异步任务中运行的代码不应执行可能阻塞的操作。在也运行其他任务的线程上运行的任务中执行的阻塞操作将阻塞整个线程,从而阻止其他任务的运行。

相反,Tokio 提供了两个用于在异步上下文中运行阻塞操作的 API:task::spawn_blockingtask::block_in_place

请注意,如果你从异步代码中调用非异步方法,则该非异步方法仍处于异步上下文中,因此你也应避免在其中进行阻塞操作。这包括在异步代码中销毁的对象的析构函数。

§spawn_blocking

task::spawn_blocking 函数类似于上一节讨论的 task::spawn 函数,但它不是在 Tokio 运行时上生成非阻塞 future,而是在专用于阻塞任务的线程池上生成阻塞函数。例如:

use tokio::task;

task::spawn_blocking(|| {
    // do some compute-heavy work or call synchronous code
});

就像 task::spawn 一样,task::spawn_blocking 返回一个 JoinHandle,我们可以使用它等待阻塞操作的结果:

let join = task::spawn_blocking(|| {
    // do some compute-heavy work or call synchronous code
    "blocking completed"
});

let result = join.await?;
assert_eq!(result, "blocking completed");
§block_in_place

使用多线程运行时时,task::block_in_place 函数也可用。与 task::spawn_blocking 一样,此函数允许从异步上下文运行阻塞操作。但是,与 spawn_blocking 不同,block_in_place 通过将当前工作线程转换为阻塞线程来工作,并将该线程上运行的其他任务移动到另一个工作线程。这可以通过避免上下文切换来提高性能。

例如:

use tokio::task;

let result = task::block_in_place(|| {
    // do some compute-heavy work or call synchronous code
    "blocking completed"
});

assert_eq!(result, "blocking completed");
§yield_now

此外,本模块还提供了一个 task::yield_now 异步函数,它类似于标准库的 thread::yield_now。调用并 await 此函数将使当前任务向 Tokio 运行时的调度器让步,从而允许调度其他任务。最终,让步的任务将被再次 poll,从而允许它执行。例如:

use tokio::task;

async {
    task::spawn(async {
        // ...
        println!("spawned task done!")
    });

    // Yield, allowing the newly-spawned task to execute first.
    task::yield_now().await;
    println!("main task done!");
}

模块§

coop
Utilities for improved cooperative scheduling.
futures
Task-related futures.

结构体§

AbortHandle
An owned permission to abort a spawned task, without awaiting its completion.
Id
An opaque ID that uniquely identifies a task relative to all other currently running tasks.
JoinError
Task failed to execute to completion.
JoinHandle
An owned permission to join on a task (await its termination).
JoinSet
A collection of tasks spawned on a Tokio runtime.
LocalEnterGuard
Context guard for LocalSet
LocalKey
A key for task-local data.
LocalSet
A set of tasks which are executed on the same thread.

函数§

id
Returns the Id of the currently running task.
spawn
Spawns a new asynchronous task, returning a JoinHandle for it.
spawn_blocking
Runs the provided closure on a thread where blocking is acceptable.
spawn_local
Spawns a !Send future on the current LocalSet or LocalRuntime.
try_id
Returns the Id of the currently running task, or None if called outside of a task.
yield_now
Yields execution back to the Tokio runtime.