首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何从可观测序列计算ETA?

如何从可观测序列计算ETA?
EN

Stack Overflow用户
提问于 2018-07-19 16:03:27
回答 2查看 156关注 0票数 1

我有一个方法,在给定的时间用%完成发送推送更新。

代码语言:javascript
运行
复制
public Task MyMethod(IObserver<double> progress)
{
   ...
}

我的消费者这样做:

代码语言:javascript
运行
复制
ISubject<double> progressObserver = new Subject<double>();
await MyMethod(progressObserver);

它订阅subject以监视更新:

代码语言:javascript
运行
复制
progressObserver.Subscribe(percent => Console.WriteLine(percent));

这很好,但是我想计算一个ETA (估计完成的时间)。我知道考虑到时间和百分比是可以计算出来的,但是如何计算呢?

当然,有一种使用Observables (System.Reactive)的优雅方法,可能使用最后的n百分比通知以及它们之间的时间来估计100%的完成时间。

但是,对不起,我不知道如何做得好和优雅。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-20 03:45:42

以下是我对此的看法:

代码语言:javascript
运行
复制
IObservable<Timestamped<double>> estimatedCompletion =
    progressObservable
        .Timestamp()
        .Buffer(2, 1)
        .Where(x => x.Count() == 2)
        .Scan((a, b) => a.Take(1).Concat(b).Take(1).Concat(b.Skip(1)).ToList())
        .Select(x => new
        {
            current = x[1].Value,
            delta = x[1].Timestamp.Subtract(x[0].Timestamp),
        })
        .Select(x => new
        {
            x.current,
            rate = x.current / x.delta.TotalSeconds,
        })
        .Select(x => new
        {
            x.current,
            estimated = DateTimeOffset.Now.AddSeconds((1.0 - x.current) / x.rate),
        })
        .Select(x => new Timestamped<double>(x.current, x.estimated));

这会产生一个IObservable<Timestamped<double>>,其中时间戳是可观察到的到达1.0 (或100%)的估计DateTimeOffset

关键是,它使用.Buffer(2, 1).Where(x => x.Count() == 2)作为可观察值生成值对,然后使用看似复杂的.Scan((a, b) => a.Take(1).Concat(b).Take(1).Concat(b.Skip(1)).ToList())始终生成第一个值与最新值的对。

然后,它只是简单地做了一系列步骤的估计计算。

因为原始序列从0.0到1.0,这将最准确地磨练到最后一次。这只是一个估计,但如果实现的步骤是相当一致的,那么这将是相当准确的。

您可以使用以下代码进行测试:

代码语言:javascript
运行
复制
var rnd = new Random();
var progressObservable = Observable.Generate(0, x => x <= 100, x => x + 1, x => x / 100.0, x => TimeSpan.FromSeconds(rnd.NextDouble()));
票数 1
EN

Stack Overflow用户

发布于 2018-07-19 16:53:31

看起来可能是这样的:

代码语言:javascript
运行
复制
var secondsRemaining = progressObservable
    .Timestamp()
    .Buffer(5, 1)
    .Select(l => ((l[4].Timestamp - l[0].Timestamp).TotalMilliseconds / (l[4].Value - l[0].Value)) * (100 - l[4].Value))
    .Select(msRemaining => msRemaining / 1000);

解释:

每次进度更新,

  • .Buffer(5, 1)发布了最近5次进度更新的列表。
  • .Timestamp()将时间戳钉在每一个上。
  • 第一个Select运算符计算最遥远的时间戳和最近的时间戳之间的毫秒数,除以所取得的进展,然后乘以剩余的进度,输出剩余的毫秒。
  • 最后一个Select除以1000,以达到剩下的秒。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51427263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档