代码之家  ›  专栏  ›  技术社区  ›  SuperJMN

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

  •  1
  • SuperJMN  · 技术社区  · 7 年前

    我想通知用户完成操作的估计剩余时间。长时间操作发生在如下序列中:

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

    每个 Process(x) 通话可能需要几秒钟才能完成。

    我想知道一种简单明了的方法,可以在预测可枚举项时动态估计剩余值。

    可能使用 System.Reactive ?

    1 回复  |  直到 7 年前
        1
  •  4
  •   DavidG    7 年前

    首先,这是不可能的 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; }
    }
    

    和习俗 选择 方法:

    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