Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.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
C# 反应式扩展:成批处理事件+;在每个批次之间添加延迟_C#_System.reactive_Windows Runtime - Fatal编程技术网

C# 反应式扩展:成批处理事件+;在每个批次之间添加延迟

C# 反应式扩展:成批处理事件+;在每个批次之间添加延迟,c#,system.reactive,windows-runtime,C#,System.reactive,Windows Runtime,我有一个应用程序,它在某些时候几乎同时引发1000个事件。我想做的是将事件批处理成50个项目的块,并开始每10秒处理一次。在开始新的批处理之前,无需等待批处理完成 例如: 10:00:00: 10000 new events received 10:00:00: StartProcessing (events.Take(50)) 10:00:10: StartProcessing (events.Skip(50).Take(50)) 10:00:15: StartProcessing (even

我有一个应用程序,它在某些时候几乎同时引发1000个事件。我想做的是将事件批处理成50个项目的块,并开始每10秒处理一次。在开始新的批处理之前,无需等待批处理完成

例如:

10:00:00: 10000 new events received
10:00:00: StartProcessing (events.Take(50))
10:00:10: StartProcessing (events.Skip(50).Take(50))
10:00:15: StartProcessing (events.Skip(100).Take(50))
有什么办法可以做到这一点吗?我认为反应式扩展是可行的,但其他解决方案也是可以接受的

我试着从这里开始:

        var bufferedItems = eventAsObservable
            .Buffer(15)
            .Delay(TimeSpan.FromSeconds(5)
但是注意到延迟并没有像我希望的那样起作用,而是所有批次同时开始,尽管延迟了5秒

我还测试了Window方法,但没有发现行为上的任何差异。我想窗口中的TimeSpan实际上意味着“在接下来的10秒内处理所有事件:

        var bufferedItems = eventAsObservable
            .Window(TimeSpan.FromSeconds(10), 5)
            .SelectMany(x => x)
            .Subscribe(DoProcessing);
我正在使用Rx Main 2.0.20304-beta版。

试试这个:

    var bufferedItems = eventAsObservable
        .Buffer(50)
        .Do(_ => { Thread.Sleep(10000); });

如果不希望睡眠线程,可以执行以下操作:

var tick = Observable.Interval(TimeSpan.FromSeconds(5));

eventAsObservable
.Buffer(50)
.Zip(tick, (res, _) => res)
.Subscribe(DoProcessing);

有一个特定的缓冲区方法重载用于此:


这是一个令人惊讶的难以解决的问题。更重要的是,使用
Zip
操作符将可观测值与
可观测值对齐的诱人想法。间隔
,存在缺陷且效率极低。
Zip
操作符的主要问题是,当与不对称可观测值一起使用时,它会缓冲ele最快生成的可观察对象的集合,在长期订阅期间可能导致大量内存分配。IMHO此运算符的使用应限于预期在长期内生成相等(或接近相等)数量元素的可观察对象对

Zip
+
Observable.Interval
组合的错误行为在
Observable.Interval
发出的值比源可观测值快时出现。在这种情况下,
Observable.Interval
发出的多余值会被缓冲,因此当源可观测值发出下一个元素时,就会出现already缓冲的
间隔
值以形成一对,从而违反“元素之间的最小间隔”策略

下面是自定义
WithInterval
运算符的实现,该运算符在可观测序列的连续元素之间施加最小间隔。然后,该运算符将用于解决此问题的特定问题,该问题涉及缓冲区而不是单个元素:

/// <summary>Intercepts a minimum interval between consecutive elements of an
/// observable sequence.</summary>
public static IObservable<T> WithInterval<T>(this IObservable<T> source,
    TimeSpan interval, IScheduler scheduler = null)
{
    return source
        .Scan((Observable.Return(0L), (IObservable<T>)null), (state, x) =>
        {
            var (previousTimer, _) = state;
            var timer = (scheduler != null ? Observable.Timer(interval, scheduler)
                : Observable.Timer(interval)).PublishLast();
            var delayed = previousTimer.Select(_ => x).Finally(() => timer.Connect());
            return (timer, delayed);
        })
        .Select(e => e.Item2)
        .Concat();
}
用法示例:

var subscription = eventAsObservable
    .BatchWithInterval(50, TimeSpan.FromSeconds(10))
    .Subscribe(DoProcessing);

我希望我能不止一次地更新它!我花了三个小时试图解决它。我有一个类似的问题。但我希望下一批不在最后一批完成之前开始。@Zuendi您可能会发现这很有趣:这不是OP想要的。他希望每5秒处理一次。如果缓冲区有50秒,这个扩展也会触发元素。这可能在5秒前发生。。。
/// <summary>Projects each element of an observable sequence into consecutive
/// non-overlapping buffers which are produced based on element count information,
/// intercepting a minimum interval between consecutive buffers.</summary>
public static IObservable<IList<T>> BatchWithInterval<T>(this IObservable<T> source,
    int count, TimeSpan interval, IScheduler scheduler = null)
{
    return source.Buffer(count).WithInterval(interval, scheduler);
}
var subscription = eventAsObservable
    .BatchWithInterval(50, TimeSpan.FromSeconds(10))
    .Subscribe(DoProcessing);