昨天我们稍微接触了下Stream
,文档这部分应该也是还没完善的,说了几个方法就没了。
今天我们接着学
Future
现在我们已经学会如何使用async/await
了,也可以用于简单的异步场景了。
但是对于真实的异步情况来说一般需要并发的执行多个不同的异步运算。
接下来我们要接触一些方法涉及到上面的情况。
join!
:等待所有futures
都执行完毕。select!
:等待其中一个future
完成。Spawning
:创建一个任务,它会携带一个future
.(其实day2
已经接触过了)FuturesUnordered
:一组future
,它们从它们子future
收取(yields
)结果futures::join
这个宏的作用类似JoinHandle
的join
方法,可以等待并发的多个不同的异步future
完成再结束。
先来看下例子
这个异步函数返回了两个异步任务,但是这其实没有想象中的块,因为它俩都是异步函数,get_music
会被get_book
堵塞。
这个时候我们就可以使用futures::join!
来将它俩并发处理。
虽然输出的时候还是要等待它俩完成才会输出,但是它俩在等待的过程是并发的,所以不会有堵塞。
来稍微看下源码
是一个声明宏,给传入的异步任务分别调用futures_macro::join_internal
的宏。
这是个属性宏
真正处理的源码是下面这个
简单的说这里将它俩合并成一个异步任务,然后等待它们完成。
原来的情况是music
的会一直不动,直到第一个异步也就是book
的ready
之后才会执行。
现在变成它俩同时进入执行器的接收器队列中,这样就不会堵塞了。
注意这里手动调用了future
的poll
方法,所以外面也就不用调用await
来处理了。
另外也不要这样做:其它语言中可以这样并发的做,但是在rust
中不行,不会报错,但是依旧会堵塞。
如果你的future
返回的数据类型是Result
的,那么这里最好用try_join!
来代替join!
。
因为join!
会一直执行下去,即使是这个数据返回的是Err
变体。而try_join!
会如果遇到Err
变体会立即终止。
直接来看下用法
注意future
的Err
类型得是一样的。
我们可以用futures::future::TryFutureExt
里的.err_into
或者..map_err(|e| ...)
来合并错误类型
这个futures::select
宏同样可以同时执行多个futures
,不过不同于join!
,select!
只要有其中一个完成就会返回。
有些类似前端promise.all
和promise.race
的区别。
select!
支持default
和complete
两条分支:
default
用在你模式啥都没匹配到但是已经结束咧~也就是都执行完了。complete
用在当所有分支都完成并且都被选择了的场景。一般select!
搭配循环且在结束的时候被调用。上面第一个例子中,我们并没有提及.fuse
这个方法。它用在原本应该是.await
的地方。
它是必须调用的,因为使用select!
的前提是future
得实现Unpin
和FusedFuture
这俩trait
。
实现Unpin
的原因是select!
的过程中并不是使用pin
里包裹的值,而是一个可变引用,因为这样就不需要获取值的所有权,未完成的future
就可以再次使用。
实现FusedFuture
的原因类似Unpin
,为了确保select
在future
执行结束之后不能再调用这个future
的poll
。FusedFuture
用来跟踪future
是否已经完成。上面第二个例子中future::ready
返回的future
实现了FusedFuture
,那么这个时候就不会再poll
了。(Stream
中也是差不多的:FusedStream
)
来看下例子
使用.next()/.try_next()
将产生实现FusedFuture
的future
有一个很难描述但是很方便的函数叫Fuse::terminated()
,它可以用来创建一个空的已经被终止的(terminated
)future
,这个空future
将会被一个准备运行的future
填充。
它能用于select
循环过程中存储某个select
自己产生的future
。相当于select
作用域外初始化一个future
,等会在select
循环过程中存储某个被创建的future
。
我们先来看下Fuse::terminated
的例子
匹配到new_num
的时候会被缓存到run_on_new_num_fut
这个空future
里。
当这个future
完成后就会离开这个空future
。
或者这个future
倒计时结束后依旧还没运行,这个时候也会被踢出去。
可以调用is_terminated
判断当前是什么状态。
注意.select_next_some()
方法只能用于select
时branch
是Some(_)
模式的场景,None
会直接忽略。
然后再来看个FuturesUnordered
的例子
和第一个例子不同,这里所有的future
(相同的future
)都会被执行并且会输出结果
官方文档未完善
同上
同上
莫得总结
这一章很潦草,即使是非TODO
的,也就是简单的说一下怎么用。
编辑于 2023-02-01 09:16・IP 属地广东