昨天我们知道了异步执行的流程/原理
今天我们可以开始学怎么用了
在之前day1
的引子以及昨天的定时器例子中我们有使用到它俩,今天我们再来看下细节。
和同步的堵塞代码不同,异步可以绕开堵塞的问题,让线程先绕过这块事件先去执行别的。
我么来看下例子
这是个简单的场景。
注意异步函数返回的内容不一定是Future<output>
类型的,如果不搭配.await
的话。
可以类比前端async/await
的用法,在不用await
的时候返回的是一个promise
类型的数据。
我们上一节知道这个过程是lazy
的,只有被wake
的task
才开始干活。
如果它执行时判断不是Ready
状态,这个task
的future
就会让出当前线程的控制权,让它去被别的任务占有,直到它所在的task
被唤醒,又开始争夺正宫的位置。
和传统的函数不同,异步函数默认会将引用或者非'static
的参数作为返回类型Feture<output>
的生命周期(逻辑与运算,作为lifetime bound
)
比如
一般上下文中是不太需要担心的,但是如果涉及到多线程之间或者多任务之间,那就比较复杂了。
将引用作为参数的异步数转换为'static Future
的一种常见解决方法是将参数与异步块中对异步函数的调用捆绑在一起:
我们把x
和异步函数绑到了一起,这样这个x
的引用的作用域就和异步函数调用的作用域一样了。
异步块(block
)/闭包都可以用move
这个关键字,和常规闭包有些像。一个异步move
的块将会获取引用变量的所有权,它允许这个变量的生命周期比当前block
的长,但是不允许它被其他代码使用。
来看个例子
因为异步的原因导致这个数据不知道什么时候才会被用到,所以为了保证不会数据竞争直接不允许其它地方访问这个数据,即使这个时候这个异步块已经await
完返回了,既然block
都没了也自然被释放了。
.await
我们之前有提到过这一点,在多线程的场景下,一个future
在不同线程之前穿插。这就需要保证这个future
依赖的数据也是能穿插的,也就是实现Send
和Sync
这俩trait
。
如果没有,那这将会是unsafe
的。即使是加锁,加锁还有可能造成死锁。
为了避免这些场景,尽量用futures::lock
里的Mutex
替代std::sync
的Mutex
。
今天的好像还是理论偏多。。。。。
发布于 2023-01-29 23:30・IP 属地广东