Rust 如何关闭已修改并正在执行的“futures::sync::mpsc::Receiver”流?
我希望能够沿着这些路线做一些事情,以便异步关闭接收器流:Rust 如何关闭已修改并正在执行的“futures::sync::mpsc::Receiver”流?,rust,rust-tokio,Rust,Rust Tokio,我希望能够沿着这些路线做一些事情,以便异步关闭接收器流: extern crate futures; extern crate tokio; use futures::future::lazy; use futures::stream::AndThen; use futures::sync::mpsc::Receiver; use futures::{Future, Sink, Stream}; use std::sync::{Arc, Mutex}; use tokio::timer::{
extern crate futures;
extern crate tokio;
use futures::future::lazy;
use futures::stream::AndThen;
use futures::sync::mpsc::Receiver;
use futures::{Future, Sink, Stream};
use std::sync::{Arc, Mutex};
use tokio::timer::{Delay, Interval};
fn main() {
tokio::run(lazy(|| {
let (tx, rx) = futures::sync::mpsc::channel(1000);
let arc = Arc::new(Mutex::<Option<AndThen<Receiver<u32>, _, _>>>::new(None));
{
let mut and_then = arc.lock().unwrap();
*and_then = Some(rx.and_then(|num| {
println!("{}", num);
Ok(())
}));
}
let arc_clone = arc.clone();
// This is the part I'd like to be able to do
// After one second, close the `Receiver` so that future
// calls to the `Sender` don't call the callback above in the
// closure passed to `rx.and_then`
tokio::spawn(
Delay::new(std::time::Instant::now() + std::time::Duration::from_secs(1))
.map_err(|e| eprintln!("Some delay err {:?}", e))
.and_then(move |_| {
let mut maybe_stream = arc_clone.lock().unwrap();
match maybe_stream.take() {
Some(stream) => stream.into_inner().close(),
None => eprintln!("Can't close non-existent stream"), // line "A"
}
Ok(())
}),
);
{
let mut maybe_stream = arc.lock().unwrap();
let stream = maybe_stream.take().expect("Stream already ripped out"); // line "B"
let rx = stream.for_each(|_| Ok(()));
tokio::spawn(rx);
}
tokio::spawn(
Interval::new_interval(std::time::Duration::from_millis(10))
.take(10)
.map_err(|e| {
eprintln!("Interval error?! {:?}", e);
})
.fold((tx, 0), |(tx, i), _| {
tx.send(i as u32)
.map_err(|e| eprintln!("Send error?! {:?}", e))
.map(move |tx| (tx, i + 1))
})
.map(|_| ()),
);
Ok(())
}));
}
但是,行A运行是因为我必须移动行B上的流才能调用其中的每个。就我所知,如果我不为每一个或类似的东西打电话,我根本无法执行第三个。我无法在不实际移动对象的情况下调用.for\u each,因为for\u each是一个移动方法
我能做我想做的事吗?这似乎是绝对可能的,但也许我遗漏了一些明显的东西
我使用的期货价格为0.1,东京价格为0.1。你可以使用类似的板条箱来实现这一点。在这里,我使用了流包装器,它接受现有流并返回一个值,您可以使用该值在以后取消该流:
use futures::{
future::lazy,
{Future, Sink, Stream},
}; // 0.1.25
use stream_cancel::Valved; // 0.4.4
use tokio::timer::{Delay, Interval}; // 0.1.13
fn main() {
tokio::run(lazy(|| {
let (tx, rx) = futures::sync::mpsc::channel(1000);
let (trigger, rx) = Valved::new(rx);
tokio::spawn({
rx.for_each(|num| {
println!("{}", num);
Ok(())
})
});
tokio::spawn({
Delay::new(std::time::Instant::now() + std::time::Duration::from_secs(1))
.map_err(|e| eprintln!("Some delay err {:?}", e))
.map(move |_| trigger.cancel()),
});
tokio::spawn({
Interval::new_interval(std::time::Duration::from_millis(10))
.take(10)
.map_err(|e| eprintln!("Interval error?! {:?}", e))
.fold((tx, 0), |(tx, i), _| {
tx.send(i)
.map_err(|e| eprintln!("Send error?! {:?}", e))
.map(move |tx| (tx, i + 1))
})
.map(|_| ()),
});
Ok(())
}));
}
板条箱有其他类型,适合细微不同的用例,请务必查看文档
看看你自己实现这个的方法。我不会说谎,我在这一点上支持@shepmaster,你的问题很不清楚。这就是说,这感觉就像你在尝试做一些期货的mpsc部分不适合做的事情 无论如何。解释时间 无论何时组合/撰写流或未来!,每一种构图方法都采用self,而不是&self或&mut-self,我想你可能希望如此 当您到达您的代码块时:
{
let mut maybe_stream = arc.lock().unwrap();
let stream = maybe_stream.take().expect("Stream already ripped out"); // line "B"
let rx = stream.for_each(|_| Ok(()));
tokio::spawn(rx);
}
…获取时,将从弧中提取流,并将其内容替换为“无”。然后在东京反应堆上繁殖,开始处理这部分。此rx现在处于循环中,您不再可以使用。此外,您的maybe_流现在不包含任何内容
延迟一段时间后,您将尝试获取弧线a的内容。由于现在什么都没有了,您将什么都没有了,因此没有任何东西可以关闭。你的代码出错了
不要绕过mpsc::Receiver并希望破坏它,而是使用一种机制来停止流本身。您可以自己这样做,也可以使用类似stream cancel的板条箱为您这样做
DIY版本在这里,根据您的代码修改:
extern crate futures;
extern crate tokio;
use futures::future::lazy;
use futures::{future, Future, Sink, Stream};
use std::sync::{Arc, RwLock};
use std::sync::atomic::{Ordering, AtomicBool};
use tokio::timer::{Delay, Interval};
fn main() {
tokio::run(lazy(|| {
let (tx, rx) = futures::sync::mpsc::channel(1000);
let circuit_breaker:Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
let c_b_copy = Arc::clone(&circuit_breaker);
tokio::spawn(
Delay::new(std::time::Instant::now() + std::time::Duration::from_secs(1))
.map_err(|e| eprintln!("Some delay err {:?}", e))
.and_then(move |_| {
// We set the CB to true in order to stop processing of the stream
circuit_breaker.store(true, Ordering::Relaxed);
Ok(())
}),
);
{
let rx2 = rx.for_each(|e| {
println!("{:?}", e);
Ok(())
});
tokio::spawn(rx2);
}
tokio::spawn(
Interval::new_interval(std::time::Duration::from_millis(100))
.take(100)
// take_while causes the stream to continue as long as its argument returns a future resolving to true.
// In this case, we're checking every time if the circuit-breaker we've introduced is false
.take_while(move |_| {
future::ok(
c_b_copy.load(Ordering::Relaxed) == false
);
})
.map_err(|e| {
eprintln!("Interval error?! {:?}", e);
})
.fold((tx, 0), |(tx, i), _| {
tx.send(i as u32)
.map_err(|e| eprintln!("Send error?! {:?}", e))
.map(move |tx| (tx, i + 1))
})
.map(|_| ()),
);
Ok(())
}));
}
如果状态指示符设置为false,则轮询上述流;然后将结果发送给所有侦听器。如果轮询结果为Async::ReadyOne,表示流已完成,则所有侦听器通道都将关闭
如果状态指示符设置为true,则所有侦听器通道都将关闭,流将返回Async::ReadyOne并由Tokio从执行中删除
FanOut对象是可克隆的,但只有初始实例可以完成任何操作。另外,我认为我可以不包含任何代码片段,这将是一个足够高质量的问题。代码片段只是为了说明一种可能的方法,我知道它不起作用,同时也解释了为什么它不起作用。问题是什么方法有效。我理解这一点,但我不明白为什么需要编译它来回答这个问题。我不想修复代码段:我想找到一个有效的代码段。代码段自上而下都有根本性的缺陷。完全不包含代码段-这样的问题可能与主题有关,但人们也倾向于在没有试图解决它的情况下对问题持负面态度,因此这样的问题可能会被否决。是的,这正是我首先包含代码段的原因。我想证明我试过一些东西,我试过什么,为什么不起作用。潜在的答案并不需要考虑这个方法的错误,特别是当问题清楚地说明为什么它不起作用时。同时,我已经实现了一种类似的方法,实际上删除了tx,并检查tx是否已在折叠中删除。鉴于我实际编写的代码超出了问题的范围,这更有意义。然而,我真的希望从接收者的角度实现这一点,而不是从发送者的角度。这是因为我的发送者被组织在一个结构中,而我的接收者被提供给客户,客户将把他们视为特殊的。因此,作为对这个问题的直接回答,我认为流取消库更合适——它允许我完全做我想做的事情。然而,我需要进行基准测试,因为我想确保它不会损害标称流的性能。take_while中的返回是非惯用的。@RiverTam线索的名称是:mpsc-多生产者,单消费者。你也可以把你的接收器发送到一个扇出的结构中。在尝试适应spmc之后,我不得不自己写一次。不确定是否有完全满足您需求的板条箱,因此启动/停止消费者。take_while明确地做了stream cancel在引擎盖下所做的事情。它的核心使用了几乎相同的构造:-@Sébastiener nauld是的,在尝试所有这些之前,我一直在研究mpmc或spmc解决方案,但我发现没有什么能完全满足我的需要,所以我最终选择了自己的解决方案。multiqueue做了我想要的,但是它有一个bug。横梁频道也提供广播,我想,但据我所知,他们不与东京。
impl<S> Stream for FanOut<S> where S:Stream, S::Item:Clone {
type Item = S::Item;
type Error = S::Error;
fn poll(&mut self) -> Result<Async<Option<S::Item>>, S::Error> {
match self.inner.as_mut() {
Some(ref mut r) => {
let mut breaker = self.breaker.write().expect("Poisoned lock");
match breaker.status {
false => {
let item = r.poll();
match &item {
&Ok(Async::Ready(Some(ref i))) => {
breaker.registry.iter_mut().for_each(|sender| {
sender.try_send(i.clone()).expect("Dead channel");
});
item
},
_ => item
}
},
true => Ok(Async::Ready(None))
}
}
_ => {
let mut breaker = self.breaker.write().expect("Poisoned lock");
// Stream is over, drop all the senders
breaker.registry = vec![];
Ok(Async::Ready(None))
}
}
}
}