Rust Async 异步编程(一):入门

Rust 基于 await、async 的异步编程和纤程、协程的实现 它使得在 Rust 中编写异步代码变得更加简单和直观,通过结合 async/await 语法,你可以编写出清晰易读的异步代码,提高程序的并发性能和响应能力。这意味着虽然异步操作本身不会启动新线程,但它们可以在现有的线程池中的线程上执行,从而实现高效的并发处理。async 关键字用于声明一个函数是异步的,这意味着该函数可以包含挂起执行的操作(如网络请求或文件读写),而不会阻塞整个程序的执行。异步操作的执行是由运行时库(如Tokio)管理的,它们可能会在线程池中的线程上调度这些操作,以实现高效的并发处理。 阅读详情

Rust Async 异步编程(一):入门

异步编程简介

众所周知,Rust 可以让我们写出性能高且安全的软件,那么异步编程这块儿呢?是否依然在高性能的同时保证了安全?

我们先通过一张 web 框架性能对比图来感受下 Rust 异步编程的性能:

actix-vs-gin screenshot

上图并不能说 Rust 写的 actix 框架比 Go 的 gin 更好、更优秀,但是确实可以一定程度上说明 Rust 的异步性能非常的高!

简单来说,异步编程是一个 并发编程模型,目前主流语言基本都支持了,当然,支持的方式有所不同。异步编程允许我们同时并发运行大量的任务,却仅仅需要几个甚至一个 OS 线程或 CPU 核心,现代化的异步编程在使用体验上跟同步编程也几无区别,例如 Go 语言的 go 关键字,也包括我们后面将介绍的 async/await 语法,该语法是 JavaScript 和 Rust 的核心特性之一。

async 简介

async 是 Rust 选择的异步编程模型,下面我们来介绍下它的优缺点,以及何时适合使用。

async vs 其它并发模型

由于并发编程在现代社会非常重要,因此每个主流语言都对自己的并发模型进行过权衡取舍和精心设计,Rust 语言也不例外。下面的列表可以帮助大家理解不同并发模型的取舍:

  • OS线程:它最简单,也无需改变任何编程模型(业务/代码逻辑),因此非常适合作为语言的原生并发模型,Rust 选择了原生支持线程级的并发编程。但是,这种模型也有缺点,例如线程间的同步将变得更加困难,线程间的上下文切换损耗较大。使用线程池在一定程度上可以提升性能,但是对于 I/O 密集的场景来说,线程池还是不够看。
  • 事件驱动(Event driven):这个名词你可能比较陌生,如果说事件驱动常常跟回调(Callback)一起使用,相信大家就恍然大悟了。这种模型性能相当的好,但最大的问题就是存在回调地狱的风险:非线性的控制流和结果处理导致了数据流向和错误传播变得难以掌控,还会导致代码可维护性和可读性的大幅降低,大名鼎鼎的 JS 曾经就存在回调地狱。
  • 协程(Coroutines):可能是目前最火的并发模型,Go 语言的协程设计就非常优秀,这也是 Go 语言能够迅速火遍全球的杀手锏之一。协程跟线程类似,无需改变编程模型,同时,它也跟 async 类似,可以支持大量的任务并发运行。但协程抽象层次过高,导致用户无法接触到底层的细节,这对于系统编程语言和自定义异步运行时是难以接受的
  • actor 模型:它将所有并发计算分割成一个一个单元,这些单元被称为 actor,单元之间通过消息传递的方式进行通信和数据传递,跟分布式系统的设计理念非常相像。由于 actor 模型跟现实很贴近,因此它相对来说更容易实现,但是一旦遇到流控制、失败重试等场景时,就会变得不太好用
  • async/await: 该模型性能高,还能支持底层编程,同时又像线程和协程那样无需过多的改变编程模型,但有得必有失,async 模型的问题就是内部实现机制过于复杂,对于用户来说,理解和使用起来也没有线程和协程简单,好在前者的复杂性开发者们已经帮我们封装好,而理解和使用起来不够简单,正是本章试图解决的问题。

总之,Rust 经过权衡取舍后,最终选择了同时提供多线程编程和 async 编程:

  • 前者通过标准库实现,当你无需那么高的并发时,例如需要并行计算时,可以选择它,优点是线程内的代码执行效率更高、实现更直观更简单
  • 后者通过语言特性 + 标准库 + 第三方库的方式实现,在你需要高并发、异步 I/O 时,选择它就对了

async:Rust vs 其它语言

目前已经有诸多语言都通过 async 的方式提供了异步编程,例如 JavaScript ,但 Rust 在实现上有所区别:

  • Future 在 Rust 中是惰性的,只有在被轮询(poll)时才会运行, 因此丢弃一个 future 会阻止它未来再被运行, 你可以将Future理解为一个在未来某个时间点被调度执行的任务。
  • Async 在 Rust 中使用开销是零, 意味着只有你能看到的代码(自己的代码)才有性能损耗,你看不到的(async 内部实现)都没有性能损耗,例如,你可以无需分配任何堆内存、也无需任何动态调度来使用 async ,这对于热点路径的性能有非常大的好处,正是得益于此,Rust 的异步编程性能才会这么高。
  • Rust 没有内置异步调用所必须的运行时,但是无需担心,Rust 社区生态中已经提供了非常优异的运行时实现,例如 tokio
  • 运行时同时支持单线程和多线程,这两者拥有各自的优缺点,稍后会讲

Rust:async vs 多线程

虽然 async 和多线程都可以实现并发编程,后者甚至还能通过线程池来增强并发能力,但是这两个方式并不互通,从一个方式切换成另一个需要大量的代码重构工作,因此提前为自己的项目选择适合的并发模型就变得至关重要。

OS 线程非常适合少量任务并发,因为线程的创建和上下文切换是非常昂贵的,甚至于空闲的线程都会消耗系统资源。虽说线程池可以有效的降低性能损耗,但是也无法彻底解决问题。当然,线程模型也有其优点,例如它不会破坏你的代码逻辑和编程模型,你之前的同步代码,经过少量修改适配后依然可以在新线程中直接运行,同时在某些操作系统中,你还可以改变线程的优先级,这对于实现驱动程序或延迟敏感的应用(例如硬实时系统)很有帮助。

对于长时间运行的 CPU 密集型任务,例如并行计算,使用线程将更有优势。 这种密集任务往往会让所在的线程持续运行,任何不必要的线程切换都会带来性能损耗,因此高并发反而在此时成为了一种多余。同时你所创建的线程数应该等于 CPU 核心数,充分利用 CPU 的并行能力,甚至还可以将线程绑定到 CPU 核心上,进一步减少线程上下文切换。

而高并发更适合 I/O 密集型任务,例如 web 服务器、数据库连接等等网络服务,因为这些任务绝大部分时间都处于等待状态,如果使用多线程,那线程大量时间会处于无所事事的状态,再加上线程上下文切换的高昂代价,让多线程做 I/O 密集任务变成了一件非常奢侈的事。而使用 async,既可以有效的降低 CPU 和内存的负担,又可以让大量的任务并发的运行,一个任务一旦处于 I/O 或者其他等待(阻塞)状态,就会被立刻切走并执行另一个任务,而这里的任务切换的性能开销要远远低于使用多线程时的线程上下文切换。

事实上,async 底层也是基于线程实现,但是它基于线程封装了一个运行时,可以将多个任务映射到少量线程上,然后将线程切换变成了任务切换,后者仅仅是内存中的访问,因此要高效的多。

不过 async 也有其缺点,原因是编译器会为 async 函数生成状态机,然后将整个运行时打包进来,这会造成我们编译出的二进制可执行文件体积显著增大。

总之,async 编程并没有比多线程更好,最终还是根据你的使用场景作出合适的选择,如果无需高并发,或者也不在意线程切换带来的性能损耗,那么多线程使用起来会简单、方便的多!最后再简单总结下:

  • 有大量 I/O 任务需要并发运行时,选 async 模型
  • 有部分 I/O 任务需要并发运行时,选多线程,如果想要降低线程创建和销毁的开销,可以使用线程池
  • 有大量 CPU 密集任务需要并行运行时,例如并行计算,选多线程模型,且让线程数等于或者稍大于 CPU 核心数
  • 无所谓时,统一选多线程

async 和多线程的性能对比

操作async线程
创建0.3 微秒17 微秒
线程切换0.2 微秒1.7 微秒

可以看出,async 在线程切换的开销显著低于多线程,对于 I/O 密集的场景,这种性能开销累计下来会非常可怕!

一个例子

在大概理解 async 后,我们再来看一个简单的例子。如果想并发的下载文件,你可以使用多线程如下实现:

fn get_two_sites() {
    // 创建两个新线程执行任务
    let thread_one = thread::spawn(|| download("https://course.rs"));
    let thread_two = thread::spawn(|| download("https://fancy.rs"));

    // 等待两个线程的完成
    thread_one.join().expect("thread one panicked");
    thread_two.join().expect("thread two panicked");
}

如果是在一个小项目中简单的去下载文件,这么写没有任何问题,但是一旦下载文件的并发请求多起来,那一个下载任务占用一个线程的模式就太重了,会很容易成为程序的瓶颈。好在,我们可以使用 async 的方式来解决:

async fn get_two_sites_async() {
    // 创建两个不同的`future`,你可以把`future`理解为未来某个时刻会被执行的计划任务
    // 当两个`future`被同时执行后,它们将并发的去下载目标页面
    let future_one = download_async("https://www.foo.com");
    let future_two = download_async("https://www.bar.com");

    // 同时运行两个`future`,直至完成
    join!(future_one, future_two);
}

此时,不再有线程创建和切换的昂贵开销,所有的函数都是通过静态的方式进行分发,同时也没有任何内存分配发生。这段代码的性能简直无懈可击!

事实上,async 和多线程并不是二选一,在同一应用中,可以根据情况两者一起使用,当然,我们还可以使用其它的并发模型,例如上面提到事件驱动模型,前提是有三方库提供了相应的实现。

Async Rust 当前的进展

简而言之,Rust 语言的 async 目前还没有达到多线程的成熟度,其中一部分内容还在不断进化中,当然,这并不影响我们在生产级项目中使用,因为社区中还有 tokio 这种大杀器。

使用 async 时,你会遇到好的,也会遇到不好的,例如:

  • 收获卓越的性能
  • 会经常跟进阶语言特性打交道,例如生命周期、Pin 等,这些家伙可不好对付
  • 一些兼容性问题,例如同步和异步代码、不同的异步运行时(tokio 与 async-std)
  • 更昂贵的维护成本,原因是 async 和社区开发的运行时依然在不停的进化

总之,async 在 Rust 中并不是一个善茬,你会遇到更多的困难或者说坑,也会带来更高的代码阅读成本及维护成本,但是为了性能,一切都值了,不是吗?

不过好在,这些进化早晚会彻底稳定成熟,而且在实际项目中,我们往往会使用成熟的三方库,例如 tokio,因此可以避免一些类似的问题,但是对于本章的学习来说,async 的一些难点还是我们必须要去面对和征服的。

语言和库的支持

async 的底层实现非常复杂,且会导致编译后文件体积显著增加,因此 Rust 没有选择像 Go 语言那样内置了完整的特性和运行时,而是选择了通过 Rust 语言提供了必要的特性支持,再通过社区来提供 async 运行时的支持。 因此要完整的使用 async 异步编程,你需要依赖以下 trait 和外部库:

  • 所必须的 trait(例如 Future)、类型和函数,由标准库提供实现。
  • 关键字 async/await 由 Rust 语言提供,并进行了编译器层面的支持。
  • 众多实用的类型、宏和函数由官方开发的 futures 包提供(不是标准库),它们可以用于任何 async 应用中。
  • 异步代码的执行、I/O 操作、任务创建和调度等等复杂功能由社区的 async 运行时提供,例如 tokio 和 async-std。大多数 async 应用程序和一些 async crate 都依赖于特定的运行时。

还有,你在同步代码中使用的一些语言特性在 async 中可能将无法再使用

注意,Rust 也不允许你在 trait 中声明 async 函数(可以通过三方库实现)。

总之,你会遇到一些在同步代码中不会遇到的奇奇怪怪、形形色色的问题,不过不用担心,本章会专门用一个章节罗列这些问题,并给出相应的解决方案。

编译和错误

在大多数情况下,async 中的编译错误和运行时错误跟之前没啥区别,但是依然有以下几点值得注意:

  • 编译错误,由于 async 编程时需要经常使用复杂的语言特性,例如生命周期和 Pin,因此相关的错误可能会出现的更加频繁
  • 运行时错误,编译器会为每一个 async 函数生成状态机,这会导致在栈跟踪(Stack traces)时会包含这些状态机的细节,同时还包含了运行时对函数的调用,因此,栈跟踪记录(例如 panic 时)将变得更加难以解读
  • 一些隐蔽的错误也可能发生,例如在一个 async 上下文中去调用一个阻塞的函数,或者没有正确的实现 Future trait 都有可能导致这种错误。这种错误可能会悄无声息的通过编译检查甚至有时候会通过单元测试。好在一旦你深入学习并掌握了本章的内容和 async 原理,可以有效的降低遇到这些错误的概率

兼容性考虑

异步代码和同步代码并不总能和睦共处。例如,我们无法在一个同步函数中去调用一个 async 异步函数,同步和异步代码也往往使用不同的设计模式,这些都会导致两者融合上的困难。

甚至于有时候,异步代码之间也存在类似的问题,如果一个库依赖于特定的 async 运行时来运行,那么这个库非常有必要告诉它的用户,它用了这个运行时。否则一旦用户选了不同的或不兼容的运行时,就会导致不可预知的麻烦。

性能特性

async 代码的性能主要取决于你使用的 async 运行时,好在这些运行时都经过了精心的设计,在你能遇到的绝大多数场景中,它们都能拥有非常棒的性能表现。

但是世事皆有例外。目前主流的 async 运行时几乎都使用了多线程实现,相比单线程虽然增加了并发表现,但是对于执行性能会有所损失,因为多线程实现会有同步和切换上的性能开销,若你需要极致的顺序执行性能,那么 async 目前并不是一个好的选择。

同样的,对于延迟敏感的任务来说,任务的执行次序需要能被严格掌控,而不是交由运行时去自动调度,后者会导致不可预知的延迟,例如一个 web 服务器总是有 1% 的请求,它们的延迟会远高于其它请求,因为调度过于繁忙导致了部分任务被延迟调度,最终导致了较高的延时。正因为此,这些延迟敏感的任务非常依赖于运行时或操作系统提供调度次序上的支持。

以上的两个需求,目前的 async 运行时并不能很好的支持,在未来可能会有更好的支持,但在此之前,我们可以尝试用多线程解决。

async/.await 简单入门

async/.await 是 Rust 内置的语言特性,可以让我们用同步的方式去编写异步的代码。

通过 async 标记的语法块会被转换成实现了 Future trait 的状态机。 与同步调用阻塞当前线程不同,当 Future 执行并遇到阻塞时,它会让出当前线程的控制权,这样其它的 Future 就可以在该线程中运行,这种方式完全不会导致当前线程的阻塞。

下面我们来通过例子学习 async/.await 关键字该如何使用,在开始之前,需要先引入 futures 包。编辑 Cargo.toml 文件并添加以下内容:

[dependencies]
futures = "0.3"

使用 async

首先,使用 async fn 语法来创建一个异步函数:

async fn do_something() { 
    println!("go go go !");
}

需要注意,异步函数的返回值是一个 Future,若直接调用该函数,不会输出任何结果,因为 Future 还未被执行:

fn main() {
      do_something();
}

运行后,go go go 并没有打印,同时编译器给予一个提示:warning: unused implementer of Future that must be used,告诉我们 Future 未被使用,那么到底该如何使用?答案是使用一个执行器(executor),例如 block_on。

block_on 会阻塞当前线程直到指定的 Future 执行完成,这种阻塞当前线程以等待任务完成的方式较为简单、粗暴,好在其它运行时的执行器会提供更加复杂的行为,例如将多个 future 调度到同一个线程上执行。

use futures::executor::block_on;

async fn hello_world() {
    println!("hello, world!");
}

fn main() {
	// 返回一个 Future, 因此不会打印任何输出
    let future = hello_world();
    // 执行 Future 并等待其运行完成,此时 "hello, world!" 会被打印输出
    block_on(future);
}

使用 .await

在上述代码的 main 函数中,我们使用 block_on 这个执行器等待 Future 的完成,让代码看上去非常像是同步代码,但是如果你要在一个 async fn 函数中去调用另一个 async fn 并等待其完成后再执行后续的代码,该如何做?例如:

use futures::executor::block_on;

async fn hello_world() {
    hello_cat();
    println!("hello, world!");
}

async fn hello_cat() {
    println!("hello, kitty!");
}
fn main() {
    let future = hello_world();
    block_on(future); 
}

这里,我们在 hello_world 异步函数中先调用了另一个异步函数 hello_cat,然后再输出 hello, world!,看看运行结果:

warning: unused implementer of `futures::Future` that must be used
 --> src/main.rs:6:5
  |
6 |     hello_cat();
  |     ^^^^^^^^^^^^
= note: futures do nothing unless you `.await` or poll them  
...
hello, world!

不出所料,main 函数中的 future 我们通过 block_on 函数进行了运行,但是这里的 hello_cat 返回的 Future 却没有任何人去执行它,不过好在编译器友善的给出了提示:futures do nothing unless you .await or poll them ,两种解决方法:使用 .await 语法或者对 Future 进行轮询(poll)。

后者较为复杂,暂且不表,先来使用 .await 试试:

use futures::executor::block_on;

async fn hello_world() {
    hello_cat().await;
    println!("hello, world!");
}

async fn hello_cat() {
    println!("hello, kitty!");
}
fn main() {
    let future = hello_world();
    block_on(future); 
}

为 hello_cat() 添加上 .await 后,结果立刻大为不同:

hello, kitty!
hello, world!

输出的顺序跟代码定义的顺序完全符合,因此,我们在上面代码中使用同步的代码顺序实现了异步的执行效果,非常简单、高效,而且很好理解,未来也绝对不会有回调地狱的发生。

总之,在 async fn 函数中使用 .await 可以等待另一个异步调用的完成。但是与 block_on 不同,.await 并不会阻塞当前的线程,而是异步的等待 Future A 的完成,在等待的过程中,该线程还可以继续执行其它的 Future B,最终实现了并发处理的效果。

一个例子

考虑一个载歌载舞的例子,如果不用 .await,我们可能会有如下实现:

async fn learn_song() -> Song { /* ... */ }
async fn sing_song(song: Song) { /* ... */ }
async fn dance() { /* ... */ }

fn main() {
    let song = block_on(learn_song());
    block_on(sing_song(song));
    block_on(dance());
}

当然,以上代码运行结果无疑是正确的,但是,它的性能何在?需要通过连续三次阻塞去等待三个任务的完成,一次只能做一件事,实际上我们完全可以改成这样:

async fn sing_song(song: Song) { /* ... */ }
async fn learn_and_sing() {
    // 这里使用 .await 来等待学歌的完成,但是并不会阻塞当前线程,该线程在学歌的任务 .await 后,完全可以去执行跳舞的任务
    let song = learn_song().await;
    
    // 唱歌必须要在学歌之后
    sing_song(song).await;
}

async fn async_main() {
    let f1 = learn_and_sing();
    let f2 = dance();

    // join! 可以并发的处理和等待多个 Future,若 learn_and_sing Future 被阻塞,那 dance Future 可以拿过线程的所有权继续执行。若 dance 也变成阻塞状态,那 learn_and_sing 又可以再次拿回线程所有权,继续执行。
    // 若两个都被阻塞,那么 async main 会变成阻塞状态,然后让出线程所有权,并将其交给 main 函数中的 block_on 执行器
    futures::join!(f1, f2);
}

fn main() {
    block_on(async_main());
}

上面代码中,学歌和唱歌具有明显的先后顺序,但是这两者都可以跟跳舞一同存在,也就是你可以在跳舞的时候学歌,也可以在跳舞的时候唱歌。如果上面代码不使用 .await,而是使用 block_on(learn_song()), 那在学歌时,当前线程就会阻塞,不再可以做其它任何事,包括跳舞。

因此 .await 对于实现异步编程至关重要,它允许我们在同一个线程内并发的运行多个任务,而不是一个一个先后完成。若大家看到这里还是不太明白,强烈建议回头再仔细看一遍,同时亲自上手修改代码试试效果。

至此,读者应该对 Rust 的 async/.await 异步编程有了一个清晰的初步印象,下面让我们一起来看看这背后的原理:Future 和任务在底层如何被执行。

参考

  1. https://github.com/rustcn-org/async-book
  2. https://www.bilibili.com/video/BV1Ki4y1C7gj
Rust编程基础教程:异步编程入门 作者:禅与计算机程序设计艺术 1.背景介绍 异步编程(Asynchronous programming)是指在多任务环境中,主线程可以执行其他任务而不会被阻塞,从而提高应用程序的响应速度和吞吐量。异步编程在现代操作系统、Web服务器、数据库、消息中间件等领域都得到广泛应用。相比同步编程(Synchr 阅读详情

相关推荐

【Rust异步编程】Rust异步编程原理解析、标准库实现与第三方库实现详解

异步编程是一种允许程序在等待某些操作(如I/O)完成时继续执行其他任务的编程范式。与传统的同步编程相比,异步编程可以显著提高程序的吞吐量和资源利用率。 在Rust中,异步编程具有以下特点: 非阻塞执行:任务可以在等待时让出控制权 轻量级:异步任务(称为future)比线程更轻量 显式标记:使用async/await语法明确标识异步代码

景天科技苑 4万+

一文读懂Rust的async

因为这些运行时之间有很多`相通`的地方,熟悉了一个再去熟悉其它的就简单了。就像我们学习编程语言一样,学好学深一门编程语言,再去学习其它的语言就快了。不要一开始就几门语言一起学,这样很可能实际开发时这也不行那也不行换来换去还是不能开发出东西.

一个不安分的程序员 9643

034、特定场景优化(一):小目标检测的改进策略合集

本文针对工业场景中的小目标检测难题,提出了一套实战优化方案。首先从数据层面建议保持高分辨率输入(1024-1280像素)或采用切块训练策略,并适当放大标注区域。在网络结构上,提出减少下采样次数、增加高分辨率检测头、引入空间注意力机制等改进。损失函数方面推荐使用NWD匹配和QFL损失提升小目标敏感度。部署环节强调NMS优化、分辨率对齐和量化处理技巧。最后总结核心经验:优先优化数据质量而非模型结构,标注一致性比算法更重要,同时需为实际部署预留性能余量。硬件升级有时比算法调优更经济有效。

xiaoyaohou11的博客 652

Rust async,看这一篇就够了~

实战详细解释Rust Async,值得你看!

vince1998的博客 3491

iOS 取证窍门:为什么要先从 Recovery 恢复模式开始?

未记录的 DFU 代表“设备固件升级”。与专为普通用户设计的恢复模式不同,DFU 模式从来都不是为公众设计的。Apple 知识库中的任何地方都没有关于 DFU 的文档。进入 DFU 的方法主要是通过按下、按住和释放按钮的复杂操作序列,并具有精确的时间限制。在多个步骤中的任何一个步骤中,如果时间错误,都会导致重新启动设备,而不是将其切换到 DFU。另外,设备屏幕上也没有 DFU 模式的指示。如果设备成功切换到 DFU,显示屏将保持黑色。即使对于专家来说,进入 DFU 模式也可能很困难。恢复模式是最容易解释的。

2302_82041293的博客 1198

虚拟机Ubuntu连接USRP

笔记本通过网线连接USRP。

xiaozir的博客 2310

【跟小嘉学 Rust 编程】二十七、Rust 异步编程(Asynchronous Programming)

本章节讲解 Rust 的异步编程方案,我们将讲解 Future、Waker、Executor、Pin、async 和 await、Stream等主要教材参考 《The Rust Programming Language》主要教材参考 《Rust For Rustaceans》主要教材参考 《The Rustonomicon》主要教材参考 《Rust 高级编程》主要教材参考 《Cargo 指南》主要教材参考 《Rust 异步编程》并发是程序同时有多个正在运行的线程。

小嘉丶学长的博客 3243

计算机毕业设计springboot基于微信平台的二次元手办商场小程序【附源码】

选题背景: 随着二次元文化的兴起和普及,越来越多的人开始对二次元角色产生了浓厚的兴趣和喜爱。手办作为二次元文化的重要载体之一,成为了许多二次元爱好者收藏和展示的对象。然而,在传统的线下手办商场中,消费者往往面临着时间、空间和选择的限制。因此,基于微信平台的二次元手办商场小程序应运而生。 选题意义: 首先,基于微信平台的二次元手办商场小程序能够打破地域限制,使得用户可以随时随地通过手机进行购物。无论是在家中、上班途中还是旅行中,用户都能够方便地浏览和购买自己喜欢的手办,极大地提高了购物的便利性和灵活性。

拉期程序 452

详解Rust异步编程

Rust的异步编程通过async/await语法和Future特性提供了一种高效的方式来处理并发任务,尤其在I/O密集型操作中表现出色。async/await异步编程模型性能高,还能支持底层编程,同时又像线程和协程那样无需过多的改变编程模型,但async模型的问题就是内部实现机制过于复杂,对于用户来说,理解和使用没有线程和协程简单。

yang1fei2的博客 3141

【水下小目标检测】SWIPENet与样本重加权:应对模糊与噪声的深度学习策略

本文深入探讨了水下小目标检测的挑战与解决方案,重点介绍了SWIPENet网络架构与IMA样本重加权算法。通过空洞卷积模块、特征金字塔重构和多尺度预测机制,SWIPENet有效提升了模糊目标的检测精度。结合Invert Multi-Class Adaboost算法,系统性地解决了水下环境中的样本不均衡问题,在URPC数据集上实现了48.8%的mAP,特别适合海洋生物检测等应用场景。

weixin_29057163的博客 349

YOLOv8改进策略【注意力机制篇】| CVPRW-2024 分层互补注意力混合层 H-RAMi 针对低质量图像的特征提取模块

许多证据表明层次化网络对图像恢复(IR)任务通常不太有效,因为IR的目标是逐个预测像素值(密集预测),而缩小特征图会丢失重要的像素级信息。然而,层次化结构有降低时间复杂度以及学习语义级和像素级特征表示的优点。为了弥补缺点并利用优点,设计了H - RAMi层。

Limiiiing的博客 379

【Rust异步】async和await异步编程实战:高并发任务处理全解析

async 和 await 是 Rust 中用于异步编程的关键字。 async 用于定义异步函数,表示函数体中包含异步代码。 await 用于等待异步操作完成,并返回异步操作的结果。 • 异步函数使用 async 关键字定义,并返回实现了 Future Trait 的类型。 异步函数可以在其他异步函数中使用 await 关键字等待异步操作完成。 调用异步函数时,会返回一个实现了 Future Trait 的对象,可以通过调用.await 方法等待结果。

景天科技苑 2万+

SST专题(2-2)MMC-SST 输入级的工作原理及数学模型

本文研究了MMC-SST和iMMC-SST的电路结构及工作原理。系统由前级MMC电路和后级DC/DC电路组成,MMC负责电能转换和能量存储,DC/DC电路进行电压电流调节。重点分析了半桥型子模块(SM)的开关组态和工作原理,建立了平均值模型,推导了上下桥臂电压方程和环流特性。研究表明,通过合理控制子模块充放电模态可维持端口电压平衡,上下桥臂电压调控可影响网侧功率吸收,而环流特性对中压直流侧电压具有重要影响。

嵌入式老牛的博客 773

Rust异步编程 Async Await 入门

要了解什么是异步代码,我们首先来谈谈同步代码。println!println!上述语句按照明确的顺序执行,从上到下一个接一个地执行。” 打印,然后读取并打印Cargo.toml的内容。这种模式在正常操作下非常好 - 但有时代码需要在当前上下文在等待其他内容时暂停 - 这通常称为阻塞。换句话说,当一段代码被阻塞时,它实际上处于暂停状态,等待特定操作完成才能继续。例如,当等待文件系统、网络通信、数据库事务甚至一段时间过去时,就会发生这种情况。在此阻塞状态期间,程序保持空闲状态,无法同时执行其他任务。

xuejianxinokok的专栏 1657

深度学习在传感器数据分析中的创新应用

传感器是物理世界与数字世界的“接口”,其生成的高维、时序、多源数据蕴含着设备状态、环境变化、用户行为等关键信息。传统传感器数据分析依赖手工特征工程与简单机器学习模型,难以应对复杂场景下的非线性、长程依赖与实时性需求。深度学习通过自动特征提取非线性建模与端到端学习,成为传感器数据处理的革命性工具。本文从概念基础理论框架架构设计实现机制到实际应用,系统拆解深度学习与传感器数据的融合逻辑,结合工业预测维护医疗健康监测智能交通等场景,揭示其技术边界与未来演化方向。

大数据洞察的博客 568

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Rust 异步编程详解(async/await)

Rust异步编程通过async/await语法和Future trait实现高效I/O处理,核心机制包括状态机模型和运行时调度。文章详细解析了异步编程基础、核心组件(Future trait、async/await语法)、工作流程,并提供了HTTP请求等代码示例。同时探讨了错误处理、任务取消、Pin/Unpin等高级话题,比较了不同运行时的适用场景。最佳实践建议选择合适运行时、避免阻塞操作,并指出异步编程在性能和安全方面的优势,以及调试复杂度等限制。附带的并发网络请求示例展示了tokio运行时的实际应用,包

本博客分享软硬件一体化开发实战。硬件涵盖 PCB 设计、STM32 等 MCU 底层开发;软件包含 C++、Rust,Qt/QML、PyQt、Slint、TouchGFX、LVGL 各类 GUI 框架。方便软硬件开发者查阅学习。欢迎关注! 2224

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Rust 异步编程 async/await

Rust 的异步编程模型 async/await 提供了一种简洁、高效的方式来处理异步操作。它允许开发者以一种更自然和直观的方式来处理异步操作,同时保持了 Rust 的安全性和性能。通过 async/await,Rust 为异步编程提供了一流的语言支持,使得编写高效且可读性强的异步程序变得更加容易。

QQ672168的博客 1344

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

异步编程:Rust 的 async/await 详解

Rust异步编程模型通过async/await语法、Future Trait和异步运行时(Tokio/async-std)实现高效非阻塞I/O操作。async标记异步函数返回Future,await暂停但不阻塞线程,允许运行时调度其他任务。异步运行时管理任务调度和事件循环,Tokio提供完整的异步I/O支持。通过tokio::spawn和select!宏可实现并发任务处理。这种模型结合Rust的内存安全特性,使开发者能编写高性能、可维护的异步应用,特别适合I/O密集型场景。

2501_93870138的博客 993

Rust异步编程入门与实战:从理论到实践

在开始之前,我想先聊聊什么是异步编程。异步编程是一种编程范式,它允许程序在等待某些操作(如网络请求、文件I/O等)完成时,继续执行其他任务,而不是阻塞等待。传统的同步编程模型中,当我们执行一个耗时操作时,程序会一直等待这个操作完成,然后才继续执行下一步。这种方式在处理并发任务时效率较低,因为CPU在等待I/O操作时处于空闲状态。而异步编程模型中,当我们执行一个耗时操作时,程序会注册一个回调函数,然后继续执行其他任务。当耗时操作完成时,系统会通知程序,然后执行相应的回调函数。

no1coder的博客 1万+

Rust异步编程之async与.await

介绍了Rust中异步编程基本语法async与.await和Future,以及常见的运行时

飞鹰技术 1098

Rust异步编程async/.await原理解析(一)

在这个教程中我们将详细分析rust异步代码async/.await的内部运行机制。我们将使用async-std库而不是tokio,因为这是第一个支持async/.await语法的rust库。async/.await原理解析教程分为两部分,这是第一部分。 区块链开发教程链接:以太坊 | 比特币 | EOS | Tendermint | Hyperledger Fabric | Omni/USDT | Ripple 0、准备Rust练习环境 首先让我们先创建一个Cargo项目: ~$ cargo new -

新缸中之脑 1万+

PyO3异步编程教程:async/await如何打通Rust async运行时与Python asyncio生态

PyO3 是 Python 解释器的官方 Rust bindings 库,其异步编程能力(`experimental-async` 特性)让你只需在 Rust `async fn` 上加一行 `#[pyfunction]`,就能自动将其转换为 Python awaitable 对象,无缝接入 Python 的 asyncio 生态。本教程带你从零理解 PyO3 如何用 async/await 打通

gitblog_00403的博客 708

快速入门futures-await:5分钟掌握Rust异步编程新语法

想要在Rust中编写简洁优雅的异步代码吗?futures-await正是你需要的终极解决方案!这个强大的库为Rust带来了async/await语法,让异步编程变得像同步代码一样简单直观。无论你是Rust新手还是经验丰富的开发者,只需5分钟就能掌握这种革命性的异步编程新语法。✨ ## 什么是futures-await? futures-await是一个Rust异步编程库,它通过`#[async

gitblog_00309的博客 772

Rust Async 异步编程(十一):Async 生态

Rust Async 异步编程(十一):Async 生态

ProgramNovice的博客 1009

Rust异步编程——1、Async 编程简介

async是 Rust 选择的 异步编程模型,下面我们来介绍下它的优缺点,以及何时适合使用。

码刀攻城 666

异步编程革命:Rust async/await完全指南

异步编程革命:Rust async/await完全指南 本文深入探讨了Rust异步编程的核心机制,从Future执行模型与任务调度机制、Pin和Unpin的内存安全原理,到Stream流处理与多Future并发技术,最后通过异步Web服务器实战开发展示完整应用。文章详细解析了Rust异步编程的底层实现原理和高级应用技巧,为开发者提供从基础到实战的完整指南。 Future执行模型与任务调度机制 在R...

gitblog_00027的博客 1262
上一篇: Rust Web 全栈开发(十三):发布
下一篇: Rust Async 异步编程(五):执行器和系统 I/O
UestcXiye
博客等级 码龄8年 9031粉丝 1306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值