C# 无损失的反应(RX)节气门

C# 无损失的反应(RX)节气门,c#,system.reactive,C#,System.reactive,在我写之前,我认为值得一问:RX有一个节流扩展方法,如果事件发生得太快,它会丢弃事件 因此,如果您要求它将事件限制为每5秒1个,如果您在0.1秒后收到一个事件,然后在1秒后收到第二个事件,您将得到一个事件,然后是静默 我想让它在0.1秒后引发第一个事件,但在4.9秒后引发另一个事件 此外,如果我在0.1秒、1秒和2秒时接收到事件,我希望它在0.1秒、5秒时引发事件,然后什么都不引发,因此我不希望它捕获n个事件,并且在n个周期中每个周期仅释放一个事件 缓冲区的作用正好相反,它将所有内容保存5秒钟,

在我写之前,我认为值得一问:RX有一个节流扩展方法,如果事件发生得太快,它会丢弃事件

因此,如果您要求它将事件限制为每5秒1个,如果您在0.1秒后收到一个事件,然后在1秒后收到第二个事件,您将得到一个事件,然后是静默

我想让它在0.1秒后引发第一个事件,但在4.9秒后引发另一个事件

此外,如果我在0.1秒、1秒和2秒时接收到事件,我希望它在0.1秒、5秒时引发事件,然后什么都不引发,因此我不希望它捕获n个事件,并且在n个周期中每个周期仅释放一个事件

缓冲区的作用正好相反,它将所有内容保存5秒钟,然后引发事件,因此它既不是节流阀,也不是缓冲区,而是介于两者之间的东西


有没有一种方法可以在现有的框架中实现这一点,或者我需要编写一个吗?

我认为您必须编写自己的操作符,或者玩弄
窗口。像其他评论一样,我不能100%确定您的需求,但我已尝试在这些测试中捕获它们

using System;
using System.Reactive.Linq;
using Microsoft.Reactive.Testing;
using NUnit.Framework;

[TestFixture]
public class Throttle : ReactiveTest
{
    private TestScheduler _testScheduler;
    private ITestableObservable<int> _sourceSequence;
    private ITestableObserver<int> _observer;

    [SetUp]
    public void SetUp()
    {
        var windowPeriod = TimeSpan.FromSeconds(5);
        _testScheduler = new TestScheduler();
        _sourceSequence = _testScheduler.CreateColdObservable(
            //Question does the window start when the event starts, or at time 0?
            OnNext(0.1.Seconds(), 1),
            OnNext(1.0.Seconds(), 2),
            OnNext(2.0.Seconds(), 3),
            OnNext(7.0.Seconds(), 4),
            OnCompleted<int>(100.0.Seconds())
            );

        _observer = _testScheduler.CreateObserver<int>();
        _sourceSequence
            .Window(windowPeriod, _testScheduler)
            .SelectMany(window =>
                window.Publish(
                    shared => shared.Take(1).Concat(shared.Skip(1).TakeLast(1))
                )
            )
            .Subscribe(_observer);
        _testScheduler.Start();
    }

    [Test]
    public void Should_eagerly_publish_new_events()
    {
        Assert.AreEqual(OnNext(0.1.Seconds(), 1), _observer.Messages[0]);
    }

    [Test]
    public void Should_publish_last_event_of_a_window()
    {
        //OnNext(1.0.Seconds(), 2) is ignored. As OnNext(5.0.Seconds(), 3) occurs after it, and before the end of a window, it is yeiled.
        Assert.AreEqual(OnNext(5.0.Seconds(), 3), _observer.Messages[1]);
    }

    [Test]
    public void Should_only_publish_event_once_if_it_is_the_only_event_for_the_window()
    {
        Assert.AreEqual(OnNext(7.0.Seconds(), 4), _observer.Messages[2]);
        Assert.AreEqual(OnCompleted<int>(100.0.Seconds()), _observer.Messages[3]);
    }

    [Test]
    public void AsOneTest()
    {
        var expected = new[]
        {
            OnNext(0.1.Seconds(), 1),
            //OnNext(1.0.Seconds(), 2) is ignored. As OnNext(5.0.Seconds(), 3) occurs after it, and before the end of a window, it is yeiled.
            OnNext(5.0.Seconds(), 3),
            OnNext(7.0.Seconds(), 4),
            OnCompleted<int>(100.0.Seconds())
        };
        CollectionAssert.AreEqual(expected, _observer.Messages);
    }
}
使用系统;
使用System.Reactive.Linq;
使用Microsoft.Reactive.Testing;
使用NUnit.Framework;
[测试夹具]
公共级油门:反应测试
{
专用测试调度器(TestScheduler);;
私有ITestableObservable\u源序列;
私人ITestableObserver(观察者);;
[设置]
公共作废设置()
{
var windowPeriod=时间跨度从秒(5);
_testScheduler=新的testScheduler();
_sourceSequence=\u testScheduler.CreateColdObservable(
//问题:窗口是在事件开始时启动,还是在时间0时启动?
OnNext(0.1秒(),1),
OnNext(1.0秒(),2),
OnNext(2.0秒(),3),
OnNext(7.0秒(),4),
未完成(100.0.s())
);
_observer=_testScheduler.CreateObserver();
_源序列
.Window(windowPeriod,\u testScheduler)
.SelectMany(窗口=>
窗口。发布(
shared=>shared.Take(1.Concat)(shared.Skip(1.TakeLast(1))
)
)
.订阅(_观察员);
_testScheduler.Start();
}
[测试]
公共空间应该急切地发布新的事件()
{
aresequal(OnNext(0.1.Seconds(),1),_observer.Messages[0]);
}
[测试]
public void应发布窗口()的上次事件
{
//忽略OnNext(1.0.Seconds(),2)。由于OnNext(5.0.Seconds(),3)出现在它之后,窗口结束之前,因此它将被删除。
aresequal(OnNext(5.0.Seconds(),3),_observer.Messages[1]);
}
[测试]
public void应该只发布一次事件,如果它是窗口()的唯一事件
{
arenequal(OnNext(7.0.Seconds(),4),_observer.Messages[2]);
arenequal(OnCompleted(100.0.Seconds()),_observer.Messages[3]);
}
[测试]
公共网络测试()
{
预期风险值=新[]
{
OnNext(0.1秒(),1),
//忽略OnNext(1.0.Seconds(),2)。由于OnNext(5.0.Seconds(),3)出现在它之后,窗口结束之前,因此它将被删除。
OnNext(5.0秒(),3),
OnNext(7.0秒(),4),
未完成(100.0.s())
};
CollectionAssert.AreEqual(预期为,_observer.Messages);
}
}

您能解释一下第二种情况吗?A(0.1s),B(1s),C(2s)=>A(0.1s),就是这样吗?与第一个场景有什么不同?当然,塔马斯。A(0.1s)、B(1s)、C(2s)将导致A(0.1s)、B(5s)。如果我们只是对它进行评级,你可能会得到A(0.1秒)、B(5秒)、C(10秒),这是我不想要的。你是对的,结果是一样的,但输入不是。这更有意义吗?所以,不管你在5个事件中收到多少个事件,你只想要前两个,第一个在它出现的确切顺序,第二个在缓冲区间隔的边缘?听起来像是
。Window(TimeSpan)
可能是你需要的。是的,塔马斯,想象你有一个总线和一个数据库。有人向数据库写入一条记录,然后在总线上发送一条消息,由服务接收。然后它进入数据库获取记录。现在,假设写入第二条记录并发送第二条消息。如果我们使用Throttle,RX将忽略第二条消息,因此我们不会再次检查数据库,除非之后出现新的请求。如果我们使用缓冲区,在开始处理之前会有5秒的延迟。我认为你是绝对正确的,这需要一些工作。更有用的是,在看到这段代码之前,我并不知道Microsoft ReactiveTest类。我以前不得不做一些“事情”来测试,这看起来更干净。谢谢。如果你能想出一个解决方案,如果你能把它和你的测试一起发布在这里,那就太好了。这个周末我将对此进行讨论。我想要一个RX解决方案,因为我正试图在这里推动采用,这将是一个很好的展示案例。听起来不错,我强烈建议您首先拿出一套测试,这样您就知道您已经考虑了所有的标称场景和边缘案例(一个窗口中没有项目,一个窗口中只有一个项目,一个窗口中有两个项目,一个窗口中有许多项目,连续的空窗口,onError,onComplete等等。)我认为这是一个很好的建议。我不知道测试支持库,我刚从nuget安装了它,所以我可以先玩一玩,弄清楚它们是如何工作的。