被一个问题困惑了好久: 在一些业务场景下,一个远端数据可能会被多次使用,比如: get_res() 可以被多次调用,如果已经fetch 成功,就会立即返回,否则就会等待 fetch 结果。 这种写法可以避免回调函数。
const res = fetch("xxxxx");
// get_res 可以被多次调用。
async get_res() {
await res;
}
但是在rust中,future 文档里写到:一个 future 只能被 poll 一次。 否则有可能会有预期外的情况。 不知道在rust当中,有没有办法做到类似的效果
1
共 10 条评论, 1 页
评论区
写评论老哥, 你还是没理解啊, 先按你的javascript代码来说:
// 情况一: // 这里你多次调用await get_res(), get_res()返回的是不同的Promise object, // 不是同一个Promise object, 而await后返回的是get_res()调用结果, 是一个值, // 不是Promise。如果你说是这种情况, await多次没有没问题。 const value = await get_res(); // 情况二: // 这里返回的是一个Promise object var promise = get_res(); // 因为javascript Promise是一个状态机, 有pending, fulfilled和rejected // 状态, 当Promise处于fulfilled状态后, await返回的是get_res调用结果 const value1 = await promise; // promise已处于fulfilled状态, 再次await, 返回的还是同样的值 const value2 = await promise; // value2与value1相等 console.assert(value1 == value2);
如果你想说的是情况二, 但你不能在rust里这么干, 因为rust有Ownership和Move Sematics:
// 假设函数get_rest signature是这样 async fn get_res() -> SomeResponse { todo!() } // rust的async函数是"lazy"的, 这里返回的是一个Future, 而不是SomeResponse let future = get_res(); // await后返回是SomeResponse, 注意这里future已经move let value = future.await; // 因为上面的future已经move, 你不能再次await这个future, 否则编译器会直接 // 报错: use of moved value: `future` let value2 = future.await; // 这里编译无法通过
另外你对rust Future实现和Poll机制不是很了解。
NotReady已经是过期很久的文档了,认准 docs.rs 商标。
而且我不知道你看的啥文档。
再仔细看看文档吧,不要囫囵吞枣。
--
👇
apawn: 文档中写到 fuse就是返回一个 NotReady,而不是立即返回数据 ?
👇
Mike Tang: Rust中早就为咱们考虑好了这种情况,.fuse() 一下就可以。
FusedFuture 查一下。其实就相当于包了一层,防止UB。
好的,谢谢回答 。 贴的代码是js 的, 在 js 里,get_res()返回了一个Promise,这个 Promise 已经被resolve 后,如果继续await,就会直接返回结果。
主要是为了解决一种业务场景,比如需要在passport获取当前用户,passport 提供一个异步函数 async getUser();
上层业务在调用的时候,直接await getUser() 结果即可,不需要判断是否已经ready了,如果没有ready,也不需要再二次请求,而是在第一次请求完成后一起resolve。如果没有ready,就直接返回结果。
这里 rust 的实现可能和js不太一样, 如果 await 一个 future,就相当于 poll 了一次,会额外再发出一次请求。 并且,如果对于已经ready的 future,无法 await 直接获取结果 。
--
👇
chansia: 有些不太明白你想问什么?你这里多次调用
get_res
没有任何问题,因为每次调用都会产生一个不同future,每一个future都会被Executor正确处理。如果每次请求结果都一样,而你又不想产生多次网络io,你可以把请求结果缓存起来,后续直接访问这个缓存,然后定时更新缓存。另外futures文档说的不是一个future只能poll一次,而是说底层实现Executor时,尽量避免多次低效poll future,而是等到future ready通知后,poll一次就好了有些不太明白你想问什么?你这里多次调用
get_res
没有任何问题,因为每次调用都会产生一个不同future,每一个future都会被Executor正确处理。如果每次请求结果都一样,而你又不想产生多次网络io,你可以把请求结果缓存起来,后续直接访问这个缓存,然后定时更新缓存。另外futures文档说的不是一个future只能poll一次,而是说底层实现Executor时,尽量避免多次低效poll future,而是等到future ready通知后,poll一次就好了文档中写到 fuse就是返回一个 NotReady,而不是立即返回数据 ?
👇
Mike Tang: Rust中早就为咱们考虑好了这种情况,.fuse() 一下就可以。
FusedFuture 查一下。其实就相当于包了一层,防止UB。
Rust中早就为咱们考虑好了这种情况,.fuse() 一下就可以。
FusedFuture 查一下。其实就相当于包了一层,防止UB。
对对对, 就是一个future 在ready 之后,还可以继续poll 多次吗 。简单来说,就是一个 future 被 await 多次
--
👇
Mike Tang: 一个Poll是被 Poll::Ready 一次,不是只能被 poll 一次。
一个Poll是被 Poll::Ready 一次,不是只能被 poll 一次。