REPL(所有代码):https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=45f88d93b198a812877f9500f4daab52
在下面的代码中,我从一个通道接收,并根据一些逻辑返回Option<Message>
。
impl Listener {
pub async fn receive(&mut self) -> Option<Arc<Message>> {
if let Ok(message) = self.receiver.recv().await {
if message.team_id == self.team_id {
println!("this is the issue, I'm returning None and it closes the stream! block");
return None;
}
Some(message)
} else {
None
}
}
}
字符串
当我在axum处理程序中收到该消息时,我使用的是一个无限的loop
,如下所示:
let res = async_stream::stream! {
loop {
if let Some(msg) = receiver.receive().await {
yield Ok(sse::Event::default().data(msg));
}
}
};
型
但是我担心无限的loop
对于性能来说是危险的。
第一个问题
像这样使用无限循环可以吗?它总是试图获取数据吗?
我很害怕,因为我会有大量的这个函数同时存在。
第二个问题while let
版本是否与无限loop
版本相同?
我试着使用下面的代码,但是如果消息是None
,它会关闭流。为什么?
我应该用Result<>
来代替吗?怎么用?
let s = async_stream::stream! {
while let Some(msg) = receiver.receive().await {
yield Ok(sse::Event::default().data(msg));
}
};
型
1条答案
按热度按时间jdzmm42g1#
字符串
这意味着,只要
receive()
的返回值是Some(...)
,就循环。如果是None
,则退出循环。所以如果你把它翻译成
loop
版本,它会是这样的:型
这里最大的问题是您试图与
None
进行什么通信。默认情况下,receive
中的None
s表示流结束。在这种情况下,使用while let
非常有意义,因为希望在流结束后停止循环。在你的例子中,你有这样的代码:
型
它返回一个
None
,以防消息不是你想要的。现在,它为外部创建了混合信号-在一种情况下,None
用于传达流结束的信息,而在另一种情况下,它传达了消息应该被忽略的信息。你得把这两个案子分开。我有两个办法:
Option
,如Option<Option<..>>
,其中外部Option
传达流的结尾,内部Option
传达消息应该被忽略。receive
函数返回,直到流结束或收到有效消息。我个人倾向于第二种选择,我将进一步简化代码,使用
.ok()?
将Result
转换为Option
并传播None
。型
然后,使用
while let
版本,因为None
现在再次表示您的连接已结束,在这种情况下,使用loop
实际上是危险的,因为它将永远以100%的CPU功率旋转。为了回答你对
loop
的担忧,loop
本身并没有什么不好的,就像while
一样。只有当它是一个忙碌循环时才是不好的,这意味着循环内部没有等待点。但是你的循环有一个.await
,它经常挂起,所以没有CPU能量被浪费。(直到.await
实际上不再等待,比如当receive()
函数的连接关闭时)补充说明:
如果你的情况有点复杂,你需要在多个地方中止当前包的处理,你可以使用
loop
和continue
的组合来干净地实现这一点。像这样:型