如何计算完成LINQ管道的ETA?

时间:2018-01-20 23:35:00

标签: c# .net linq time system.reactive

我想告知用户完成操作所需的估计时间。长时间的操作发生在这样的序列中:

var processedItems = items.Select(x => Process(x));

每次Process(x)调用可能需要几秒钟才能完成。

我想知道一种简单而干净的方法来动态估计剩余时间,因为可投影的数量是可以预测的。

也许使用System.Reactive

1 个答案:

答案 0 :(得分:2)

首先,这对于IEnumerable<T>是不可能的,因为无法获得元素的数量。为此,您应该使用实现ICollection<T>的任何内容,这样您就可以获得number of items

其次,你不能真正使用现有的Select方法(不是没有一些黑客攻击),但你可以编写自己的方法。这是我敲了一下的内容,它会在投影期间为列表中的每个元素调用一个动作。

首先是一个保存当前进度详情的课程。

public class SelectProgress
{
    public decimal Percentage { get; set; }
    public TimeSpan TimeTaken { get; set; }
    public TimeSpan EstimatedTotalTime { get; set; }
}

自定义Select方法:

public static IEnumerable<TResult> Select<TSource, TResult>(
    this ICollection<TSource> source, 
    Func<TSource, TResult> selector, 
    Action<SelectProgress> timeRemaining)
{
    Stopwatch timer = new Stopwatch();
    timer.Start();
    var counter = 0;
    foreach (var element in source)
    {
        yield return selector(element);
        counter++;
        timeRemaining?.Invoke(new SelectProgress
        {
            Percentage = counter/(decimal)source.Count,
            TimeTaken = timer.Elapsed,
            EstimatedTotalTime = 
                TimeSpan.FromTicks(timer.Elapsed.Ticks/counter * source.Count)
        });
    }
}

并称之为:

//Let's have a list of numbers to play with
var list = Enumerable.Range(1, 20).ToList();

var results = list.Select(
    i => 
    {
        //Just an artificial delay
        Thread.Sleep(1000);
        //Return the string representation of the number, you know,
        //just something fun to do here really
        return i.ToString();
    }, 
    //Just going to output the values here, but you can choose to do whatever you like
    p => Console.WriteLine(
        $"{p.Percentage:P2}: Taken: {p.TimeTaken}, Total: {p.EstimatedTotalTime}"))
    .ToList();

此代码将生成如下输出:

5.00%: Time taken: 00:00:01.0007261, Estimated total: 00:00:20.0158420
10.00%: Time taken: 00:00:02.0015503, Estimated total: 00:00:20.0155100
15.00%: Time taken: 00:00:03.0017421, Estimated total: 00:00:20.0116180
<snip>
90.00%: Time taken: 00:00:18.0101580, Estimated total: 00:00:20.0112860
95.00%: Time taken: 00:00:19.0103062, Estimated total: 00:00:20.0108480
100.00%: Time taken: 00:00:20.0107314, Estimated total: 00:00:20.0107320