【问题标题】:LinkedList faster iteration than List?LinkedList 比 List 迭代更快?
【发布时间】:2014-01-23 18:19:55
【问题描述】:

出于某种原因,我的LinkedList 似乎优于我的List。我有一个LinkedList,因为有一部分代码我必须重新安排孩子们很多。重新排列之后的一切只是循环数据并执行计算。我之前只是使用Iterator 迭代LinkedList,但后来我认为我应该同时存储相同元素的List,这样我可以更快地迭代它们。不知何故,添加List 并对其进行迭代对于完全相同的事情要慢得多。不知道这是怎么回事,所以任何信息都有帮助。

这大概是我希望更快的代码:

class Program {
    public static void Main(string[] args) {
        var originalList = new List<Thing>();
        for (var i = 0; i < 1000; i++) {
            var t = new Thing();
            t.x = 0d;
            t.y = 0d;
            originalList.Add(t);
        }
        var something = new Something(originalList);

        for (var i = 0; i < 1000; i++) {
            var start = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            something.iterate();
            time += (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - start;
            Console.Out.WriteLine(time / (i + 1));
        }
    }

    class Thing {
        public double x {get; set;}
        public double y {get; set;}
    }

    class Something {
                    private List<Thing> things;
        private LinkedList<Thing> things1 = new LinkedList<Thing>();
        private List<Thing> things2 = new List<Thing>();

        public Class(List<Thing> things) {
            this.things = things;

            for (var i = 0; i < things.Count; i++) {
                things1.AddLast(things[i]);
                things2.Add(things[i]);
            }
        }

        public void iterate() {
            //loops like this happen a few times, but the list is never changed, only the
            //objects properties in the list
            for (var i = 0; i < things2.Count; i++) {
                                    var thing = things2[i];
                thing.x += someDouble;
                thing.y += someOtherDouble;
            }
        }
    }
}

这是我首先要做的,我认为应该更慢:

class Program {
    public static void Main(string[] args) {
        var originalList = new List<Thing>();
        for (var i = 0; i < 1000; i++) {
            var t = new Thing();
            t.x = 0d;
            t.y = 0d;
            originalList.Add(t);
        }
        var something = new Something(originalList);

        for (var i = 0; i < 1000; i++) {
            var start = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
            something.iterate();
            time += (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - start;
            Console.Out.WriteLine(time / (i + 1));
        }
    }

    class Thing {
        public double x {get; set;}
        public double y {get; set;}
    }

    class Something {
        private List<Thing> things;
        private LinkedList<Thing> things1 = new LinkedList<Thing>();

        public Class(List<Thing> things) {
            this.things = things;

            for (var i = 0; i < things.Count; i++) {
                things1.AddLast(things[i]);
            }
        }

        public void iterate() {
            //loops like this happen a few times, but the list is never changed, only the
            //objects properties in the list
            var iterator = things1.First;
            while (iterator != null) {
                var value = iterator.Value;
                value.x += someDouble;
                value.y += someOtherDouble;
                iterator = iterator.Next;
            }
        }
    }
}

【问题讨论】:

  • 你到底是如何进行基准测试的?构造函数的成本是否包含在您的测量中,每个实例调用iterate() 的频率是多少?
  • 检查这个:列表与链接列表。 stackoverflow.com/questions/169973/…
  • 我什至无法编译它。请帮我解决 public Class(List things) 的语法。
  • @tau:确保附上基准测试代码,即使它看起来微不足道。 如何执行基准测试的重要性不亚于其主题。
  • 所以据说:你需要更大的列表(或在Main 中对整个循环进行计时)才能使DateTime.Now 完全有用。它的分辨率通常与系统计时器相关联,在 NT 中,系统计时器的间隔为 10 毫秒。一旦 JITter 参与其中,10 毫秒是一个非常 长的时间。 (据说有一个Stopwatch 类更适合基准测试。试试吧。)

标签: c# .net performance data-structures


【解决方案1】:

由于无法编译,所以很难验证任何东西,所以我无法在我的机器上运行它,但仍然存在一些大问题:

  • 您应该使用DateTime.Now 来衡量性能。而是使用Stopwatch,它能够进行高保真时间测量,例如:
var stopwatch = Stopwatch.StartNew();
//do stuff here
stopwatch.Stop();
double timeInSeconds = stopwatch.Elapsed.TotalSeconds;
  • 您的算法在以下行中存在根本性缺陷:
DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond

刻度表示为整数(此处为long),除法的结果不是实数,而是被截断。例如。 55 / 7 = 7。因此,它绝对不是一种稳定的基准测试方式。

此外,使用更多元素运行基准测试并确保在发布模式下进行。

【讨论】:

  • 非常感谢您的建议!我现在无法准确衡量性能并找出它特别慢的地方。
【解决方案2】:

根据您的代码,性能缓慢的原因不是迭代,而是将元素添加到List&lt;T&gt;的动作。

post 在比较 List 和 LinkedList 方面做得非常好。 List&lt;T&gt; 是基于数组的,它被分配在一个连续的块中,所以当你向它添加更多元素时,数组会被调整大小,这会导致你的代码性能变慢。

如果你来自 C++ 世界,C# 中的 List&lt;T&gt; 相当于 STD 中的 vector&lt;T&gt;,而 LinkedList&lt;T&gt; 相当于 STD 中的 list&lt;T&gt;

【讨论】:

  • 但他并没有计时构建列表。他正在对列表进行计时迭代。因此,虽然您正确地重新分配 List&lt;T&gt; 可能会比构建 LinkedList&lt;T&gt; 慢,但该信息与问题无关。
猜你喜欢
  • 1970-01-01
  • 2012-05-16
  • 2012-11-17
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-21
  • 2012-01-31
相关资源
最近更新 更多