Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如何关闭已修改并正在执行的“futures::sync::mpsc::Receiver”流?_Rust_Rust Tokio - Fatal编程技术网

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))
            }
        }
    }
}