Tokio是多线程的吗?

5

我知道Tokio可以编写并发代码,但我不确定它是否可以并行运行。我的计算机有8个核心,所以理想情况下我最多只能运行8个线程。如果我需要更多的并发性,我会在这些线程上运行协程(使用Tokio)。

除非当然,Tokio已经是多线程的。在这种情况下,在开始时创建这八个线程将是适得其反的。所以我想问的是,Tokio默认是多线程的,还是需要我自己实现?

2个回答

13

是的,Tokio 是多线程的。默认情况下,它会创建与 CPU 核心数相同的工作线程。你可以通过 tokio::main 宏来自定义运行时创建的工作线程数量。例如:

#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() {
    // your code here
}

3

Tokio 不直接使用多线程进行并发执行,而是依赖于操作系统对异步 I/O 的支持,例如在 Linux、macOS 和 Windows 上分别使用 epoll、kqueue 和 IOCompletionPort API。这些 API 允许操作系统在单个线程上多路复用异步任务的执行,从而实现并发。

但是,Tokio 提供了抽象来自动或手动生成执行并发的任务(线程)。这些任务对于处理阻塞的 I/O 密集型任务非常有用 - 这些任务将阻止调用者返回,直到 I/O 完成。

注意:异步任务是非阻塞的,即使函数尚未完成,任务也会立即返回。底层事件循环用于处理已完成的异步任务。

Tokio 提供了多种运行时的变体:

  1. 多线程
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() {
     // Your code here
}

在这个例子中,运行时将创建10个工作线程以及主线程,并使用这些工作线程并行执行任务。
2. 单线程(即当前线程)
#[tokio::main(flavor = "current_thread")]
async fn main() {
     // Your code here
}

main() 函数在事件循环上执行异步代码。但是,可以生成新的异步任务,这些任务将与主任务并发执行。

生成新任务有助于手动分配阻塞 IO 限制任务(大部分时间都在等待 IO 完成)到多个任务中。例如:

use tokio::net::TcpListener;

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("127.0.0.1:6379").await.unwrap();

    loop {
        // Asynchronous code for the main task goes here
        let (socket, _) = listener.accept().await.unwrap();

        // A new task is spawned for each inbound socket.
        // The socket is moved to the new task and processed there.
        tokio::spawn(async move {
            process(socket).await;
        });
    }
}

你的最后一个示例会在单独的线程中运行任务吗?是否有一种方法可以指定每个生成函数是在新的线程上还是与当前线程并发运行? - financial_physician

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接