简体   繁体   English

在可观察序列中删除除最后一个样本之外的任何样本,直到消费者准备好

[英]Drop any except last sample in observable sequence until consumer is ready

There is a real-time sequence of instrumental observations IObservable<S> .有一个仪器观测的实时序列IObservable<S> There is also an async consumer function f : S -> Task<U> (with side effects) that may take time to process a value.还有一个async消费者函数f : S -> Task<U> (有副作用)可能需要时间来处理一个值。 The function must not be reentered.不得重新输入该功能。 As soon as it has returned, however, the next available sample from the stream should be passed to it.但是,一旦它返回,就应该将流中的下一个可用样本传递给它。 Additionally, the function must see the very last sample at the end of the stream.此外,该函数必须看到流末尾的最后一个样本。

It feels like this must be a pretty common pattern, but I cannot find an idiomatic solution.感觉这一定是一个很常见的模式,但我找不到惯用的解决方案。 My approach works, but rather reeks of inelegance of using a subject as an imperative signal variable in the feedback loop.我的方法有效,但在反馈循环中将主题用作命令式信号变量的做法显得有些不雅。 Is there an idiomatic solution to my problem?我的问题有惯用的解决方案吗?

static void Main() {
  var source = Observable.Interval(TimeSpan.FromMilliseconds(100)).Take(27);

  var s = source.Publish(ps => {
    var signal = new Subject<Unit>();
    return ps
      .SkipLast(1)
      .Window(signal)
      .SelectMany(w => w.Take(1))
      .Merge(ps.PublishLast().RefCount())
      .Select(x => Observable.FromAsync(() => LengthyWork(x)))
      .Concat()
      .Do(signal.OnNext);
  });
  var d = s.Subscribe();
  Thread.Sleep(5000);
  Console.WriteLine("Stopping");
  d.Dispose();
}

static async Task<Unit> LengthyWork(long n) {
  Console.WriteLine($"Processing {n}");
  await Task.Delay(800);
  return Unit.Default;
}

EDIT: The code actually does not solve the problem in question: .Merge() composition with the published last element pushes that element out of sync.编辑:代码实际上并没有解决有问题的问题: .Merge()与发布的最后一个元素的组合使该元素不同步。 In this example terms, 26 is send before the function returns from processing 24 .在这个示例术语中, 26在函数从处理24返回之前发送。

Output (note that item 26 is the last before end of stream).输出(请注意,第 26 项是流结束前的最后一项)。

Processing 0
Processing 8
Processing 16
Processing 24
Processing 26
Stopping

I couldn't find a simple solution since you also want the last value published even if it wasn't in the time frame.我找不到简单的解决方案,因为您还希望发布最后一个值,即使它不在时间范围内。

// signal to indicate we want more events to flow
var signal = new BehaviorSubject<bool>(true);
var source = Observable.Interval(TimeSpan.FromMilliseconds(100)).Take(27).Publish();
// Observable to the source but have it skip the last value (would have published the same value twice if not doing this. Ex: if take was 33 instead of 27)
var sequence = source.SkipLast(1).Publish();
// Observable that is just the lastvalue in the sequence
var last = source.PublishLast();

var d = signal.DistinctUntilChanged()
    .Where(on => on) // only let go if we have signal set to true
    .SelectMany(last.Do(_ => signal.OnCompleted()).Merge(sequence).Take(1))  // Side effect of last is to turn off signal
    .Subscribe(
        async ps =>
        {
            signal.OnNext(false); // no more values from the source
            await LengthyWork(ps);
            signal.OnNext(true); // resubscribe to the source
        });

// wire it all  up
last.Connect();
sequence.Connect();
source.Connect();
Thread.Sleep(5000);
Console.WriteLine("Stopping");
d.Dispose();

Part of the idea came from How to turn Off/Restart an Interval?部分想法来自如何关闭/重新启动间隔? from the MSDN forums.来自 MSDN 论坛。

您可以使用 MostRecent 运算符 - 我认为您需要的是他对这个问题的回答的简单版本: Reactive Extensions (Rx) - 当间隔中没有值时,具有最后一个已知值的样本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM