tokio #
tokio构建可靠的网络应用程序,同时不牺牲速度。
tokio是Rust编程语言的异步运行时。它提供了编写网络应用程序所需的构建块。它提供了针对各种系统的灵活性,从拥有数十个内核的大型服务器到小型嵌入式设备。
异步运行时 #
编程方式定义运行时 #
1[dependencies]
2tokio = {version = "^1", features = ["rt", "time"]}
1use std::time;
2fn main() {
3 let duration = time::Duration::from_secs(1);
4 tokio::runtime::Builder::new_current_thread()
5 .enable_time()
6 .build()
7 .unwrap()
8 .block_on(async {
9 tokio::time::sleep(duration).await;
10 println!("hello");
11 })
12}
tokio::runtime::Builder::new_current_thread()
: 创建了一个新的Tokio运行时构建器。new_current_thread()
表示创建一个单线程的运行时。对于简单的例子或者只需要在一个线程中运行异步代码的情况,单线程运行时就足够了。.enable_time()
: 这一步启用了Tokio运行时的定时器功能。如果没有启用定时器,tokio::time::sleep()
将无法工作。.build()
: 这根据构建器的配置创建一个Tokio运行时。.unwrap()
: 由于build()
方法返回一个Result
,这里使用unwrap()
来处理可能出现的错误。在实际生产代码中,应该使用更健壮的错误处理方式,例如match
或?
操作符。.block_on(async { ... })
: 这是Tokio运行时提供的用于运行异步代码块的方法。block_on
会阻塞当前线程,直到提供的async
块执行完成。async { ... }
: 这是一个异步代码块。在这个块中,我们可以使用await
关键字来等待异步操作完成。tokio::time::sleep(duration).await;
: 这是Tokio提供的异步sleep函数。它会使当前异步任务暂停执行指定的duration
时间(在本例中是1秒)。await
关键字表示在这里等待sleep
操作完成。这意味着当前线程不会被阻塞,而是可以去执行其他异步任务。这正是异步编程的优势所在。println!("hello");
: 在sleep
完成后,这行代码会在控制台输出 “hello”。
使用#[tokio::main]
定义运行时
#
Tokio提供了一个#[tokio::main]
宏来包装的main()函数,用来简化运行时的创建:
1[dependencies]
2tokio = {version = "^1", features = ["macros", "rt", "time"]}
1use std::time;
2#[tokio::main(flavor = "current_thread")]
3async fn main() {
4 let duration = time::Duration::from_secs(1);
5
6 tokio::time::sleep(duration).await;
7 println!("hello");
8}
这个宏会自动为我们完成以下工作:
- 创建一个Tokio运行时。
- 根据
flavor
参数配置运行时。flavor = "current_thread"
表示创建一个单线程的运行时,与之前的代码等效。如果省略flavor
参数,则默认创建一个多线程的运行时。 - 将
main
函数转换为一个异步函数,并使用block_on
来运行它。 - 启用Tokio运行时的定时器功能,因此我们不需要再手动调用
.enable_time()
。
flavor
参数决定了Tokio运行时的类型:
flavor = "current_thread"
:创建单线程的运行时。适用于简单的例子或只需要在一个线程中运行异步代码的情况。- 不指定
flavor
或使用flavor = "multi_thread"
创建多线程的运行时。适用于需要并发执行大量异步任务的情况,可以充分利用多核CPU的性能。注意flavor = "multi_thread"
需使用的features flag是rt-multi-thread
。
标记为async 的函数或代码块将返回Future
,而.await
会告诉运行时我们想要等待结果。
async
和.await
的语法允许我们编写看起来像同步代码的异步代码,但却没有使用Future
所带来的复杂性。可以将async与函数、闭包和代码块一起使用。