2016-05-31 65 views
0

我想了解構造數組的性能差異。運行下面的程序,我對下面的輸出不解:創建Javascript數組的不同方法

Time for range0: 521 
Time for range1: 149 
Time for range2: 1848 
Time for range3: 8411 
Time for range4: 3487 

我不明白爲什麼3時間超過4長,同時需要1小於2。此外,似乎映射功能是非常低效的;它有什麼用處?


function range0(start, count) { 
 
    var arr = []; 
 
    for (var i = 0; i < count; i++) { 
 
     arr.push(start + i); 
 
    } 
 
    return arr; 
 
} 
 

 
function range1(start, count) { 
 
    var arr = new Array(count); 
 
    for (var i = 0; i < count; i++) { 
 
     arr[i] = start + i; 
 
    } 
 
    return arr; 
 
} 
 

 
function range2(start, count) { 
 
    var arr = Array.apply(0, Array(count)); 
 
    for (var i = 0; i < count; i++) { 
 
     arr[i] = start + i; 
 
    } 
 
    return arr; 
 
} 
 

 
function range3(start, count) { 
 
    var arr = new Array(count); 
 
    return arr.map(function(element, index) { 
 
     return index + start; 
 
    }); 
 
} 
 

 
function range4(start, count) { 
 
    var arr = Array.apply(0, Array(count)); 
 
    return arr.map(function(element, index) { 
 
     return index + start; 
 
    }); 
 
} 
 

 
function profile(range) { 
 
    var iterations = 100000, 
 
     start = 0, count = 1000, 
 
     startTime, endTime, finalTime; 
 

 
    startTime = performance.now(); 
 

 
    for (var i = 0; i < iterations; ++i) { 
 
     range(start, count); 
 
    } 
 

 
    endTime = performance.now(); 
 

 
    finalTime = (endTime - startTime); 
 
    console.log(range.name + ': ' + finalTime + ' ms'); 
 
} 
 

 
[range0, range1, range2, range3, range4].forEach(profile);

+0

現代引擎對預分配的同類陣列進行了優化,因此可能會解釋'range1'。 – 2016-05-31 23:39:24

+0

'.map()'存在以接收現有數組並使用潛在的複雜邏輯創建一個具有相同長度的新長度,以確定基於當前成員的每個成員的值。這是一個非常方便的方法。 – 2016-05-31 23:41:10

+0

因爲.map()有它自己的工作,因爲'var arr = Array.apply(0,Array(count))'是一個非常醜陋的JS指令.. – Redu

回答

1

我不明白爲什麼3的時間超過4

我也不是。這是一個令人驚訝的結果,考慮到我的表面分析和我通過分析代碼獲得的結果。在運行Google Chrome 50的計算機上,range4range3慢兩倍。

我不得不研究你正在使用的Javascript實現,以便弄清楚爲什麼會發生這種情況。

而1採取短於2

range1執行得更快,因爲它使用一個循環,並優化內存分配,同時,使用range2功能和確實不必要的內存分配。

此外,似乎地圖功能是非常低效的;它有什麼用處?

map函數用於基於現有值的計算新的Array

[1, 2, 3, 4, 5].map(number => number * number); 
// [1, 4, 9, 16, 25] 

在我的電腦

Time for range0: 783 
Time for range1: 287 
Time for range2: 10541 
Time for range3: 14981 
Time for range4: 28243 

我的結果反映了我對於每個功能的業績預期。

每個功能

  • range0

    的表面的分析創建一個Array並且經由循環填充。這是最簡單直接的代碼。我想這可以理解爲基線進行性能比較。

  • range1

    採用Array constructor具有長度參數。這極大地優化了存儲元素所需的底層內存分配。由於元素的確切數量是事先已知的,因此隨着元素數量增長,內存不一定是realloc。當Array被實例化時,存儲所有元素所需的確切內存量只能被分配一次。

  • range2

    Applies參數列表的構造函數,用this集的數量0。這在語義上等同於Array() - 使用參數count創建參數列表的事實與函數應用程序的結果無關。實際上,它不必要地浪費時間爲空的參數列表分配內存。

    你可能想用的call

    Array.call(null, count) 
    
  • range3

    range1,但有一個功能,而不是循環使用map。初始內存分配已優化,但調用函數count時間的開銷可能很大。

    另外,map生成新的Array實例。由於該實例也具有count元素,因此優化內存分配也是有意義的,但是我不清楚這是否真的發生。儘管如此,兩個單獨的內存分配正在發生,而不是像range1那樣只有一個。

  • range4

    結合了range2range3所有的低效率。

    令人驚訝的是,它比您的計算機上的range3執行得更快。我不清楚爲什麼會發生這種情況。我想你必須調查你的Javascript特定的實現才能搞清楚。

+0

我在nodeJS 4.4.5上運行代碼。 nodeJs引擎必須做一些優化來優化range4。我同意Array.apply(null,Array(count))不是創建空數組的正確方法。我從一些樣本中複製了代碼。絕對應該使用Array.call(null,count)來代替。 – JayL