为什么使用列表,当数组更快时?
Why use Lists, when Arrays are faster?
我注意到数组的执行速度比 Haxe 的链表快得多(至少在 cpp 上)。我得到的结果如下
Main.hx:40: With 1 items, Array is 14% faster than List.
Main.hx:40: With 5 items, Array is 58% faster than List.
Main.hx:40: With 10 items, Array is 59% faster than List.
Main.hx:40: With 100 items, Array is 54% faster than List.
Main.hx:40: With 1000 items, Array is 56% faster than List.
Main.hx:40: With 10000 items, Array is 55% faster than List.
Main.hx:40: With 100000 items, Array is 52% faster than List.
这让我感到眼花缭乱。即使必须连续复制项目,Array 怎么能这么快?那为什么还要使用列表呢?
package tests;
import haxe.Timer;
class Main
{
static function main()
{
var arr:Array<Int> = new Array();
var list:List<Int> = new List();
var result = new List();
for (items in [1, 5, 10, 100, 1000, 10000, 100000]) {
var listtime = timeit(10000, function() {
for (i in 0...items)
list.add(i);
for (x in list)
result.add(x);
result.clear();
list = new List();
});
var arrtime = timeit(10000, function() {
for (i in 0...items)
arr.push(i);
for (x in arr)
result.add(x);
result.clear();
arr = new Array();
});
if (arrtime < listtime)
trace('With $items items, Array is ${Std.int((1-arrtime/listtime)*100)}% faster than List.');
else
trace('With $items items, List is ${Std.int((1-listtime/arrtime)*100)}% faster than Array.');
}
}
static public function timeit<T>(times:Int, f:Void -> T):Float {
var start = Timer.stamp();
for (i in 0...times) {
f();
}
var time = Timer.stamp() - start;
return time;
}
}
Why use Lists, when Arrays are faster?
为什么更快?当涉及到在其他列表之间插入元素或删除列表中间的元素时,链表通常要快得多。对于数组(至少是 C 风格的数组),在位置 i
插入或删除需要移动 i
之后的每个元素。使用链表,您只需更改几个指针。
再次尝试您的测试,但不是将元素推到列表的末尾,而是将它们插入到开头。
How can Array be so fast even though it has to copy around items continuously?
数组对于线性处理来说更快,因为数组内容连续存储在内存中。当您线性访问内存时,多个对象被同时提取到处理器缓存中。另一方面,链表节点分散在整个内存中,因此线性处理它们会导致在主内存中进行更多访问。读取缓存比读取主内存快得多。
And why even use Lists then?
使用链表的一个主要原因是插入新元素或删除现有元素不会使对链表中其他元素的引用(包括迭代器和指针)无效。数组不能有这样的保证。
有一篇文章广泛讨论了这个问题:
https://github.com/delahee/haxe.opt/blob/master/list_vs_array.md
TLDR:这取决于您的用例,但在某些情况下列表肯定可以更快。
我注意到数组的执行速度比 Haxe 的链表快得多(至少在 cpp 上)。我得到的结果如下
Main.hx:40: With 1 items, Array is 14% faster than List.
Main.hx:40: With 5 items, Array is 58% faster than List.
Main.hx:40: With 10 items, Array is 59% faster than List.
Main.hx:40: With 100 items, Array is 54% faster than List.
Main.hx:40: With 1000 items, Array is 56% faster than List.
Main.hx:40: With 10000 items, Array is 55% faster than List.
Main.hx:40: With 100000 items, Array is 52% faster than List.
这让我感到眼花缭乱。即使必须连续复制项目,Array 怎么能这么快?那为什么还要使用列表呢?
package tests;
import haxe.Timer;
class Main
{
static function main()
{
var arr:Array<Int> = new Array();
var list:List<Int> = new List();
var result = new List();
for (items in [1, 5, 10, 100, 1000, 10000, 100000]) {
var listtime = timeit(10000, function() {
for (i in 0...items)
list.add(i);
for (x in list)
result.add(x);
result.clear();
list = new List();
});
var arrtime = timeit(10000, function() {
for (i in 0...items)
arr.push(i);
for (x in arr)
result.add(x);
result.clear();
arr = new Array();
});
if (arrtime < listtime)
trace('With $items items, Array is ${Std.int((1-arrtime/listtime)*100)}% faster than List.');
else
trace('With $items items, List is ${Std.int((1-listtime/arrtime)*100)}% faster than Array.');
}
}
static public function timeit<T>(times:Int, f:Void -> T):Float {
var start = Timer.stamp();
for (i in 0...times) {
f();
}
var time = Timer.stamp() - start;
return time;
}
}
Why use Lists, when Arrays are faster?
为什么更快?当涉及到在其他列表之间插入元素或删除列表中间的元素时,链表通常要快得多。对于数组(至少是 C 风格的数组),在位置 i
插入或删除需要移动 i
之后的每个元素。使用链表,您只需更改几个指针。
再次尝试您的测试,但不是将元素推到列表的末尾,而是将它们插入到开头。
How can Array be so fast even though it has to copy around items continuously?
数组对于线性处理来说更快,因为数组内容连续存储在内存中。当您线性访问内存时,多个对象被同时提取到处理器缓存中。另一方面,链表节点分散在整个内存中,因此线性处理它们会导致在主内存中进行更多访问。读取缓存比读取主内存快得多。
And why even use Lists then?
使用链表的一个主要原因是插入新元素或删除现有元素不会使对链表中其他元素的引用(包括迭代器和指针)无效。数组不能有这样的保证。
有一篇文章广泛讨论了这个问题:
https://github.com/delahee/haxe.opt/blob/master/list_vs_array.md
TLDR:这取决于您的用例,但在某些情况下列表肯定可以更快。