[英]Loading large amount of data into memory - most efficient way to do this?
我有一個基於Web的文檔搜索/查看系統,我正在為客戶開發。 該系統的一部分是一個搜索系統,允許客戶端搜索文檔中包含的術語[s]。 我已經創建了必要的搜索數據文件,但是需要加載大量數據,加載所有數據需要8-20秒。 數據分為40-100個文件,具體取決於需要搜索的文檔。 每個文件都在40-350kb之間。
此外,此應用程序必須能夠在本地文件系統上運行,也可以通過Web服務器運行。
當網頁加載時,我可以生成我需要加載的搜索數據文件的列表。 必須先加載整個列表,然后才能認為網頁正常運行。
有了這個序言,讓我們來看看我現在是怎么做的。
在我知道整個網頁已加載后,我調用了一個loadData()函數
function loadData(){
var d = new Date();
var curr_min = d.getMinutes();
var curr_sec = d.getSeconds();
var curr_mil = d.getMilliseconds();
console.log("test.js started background loading, time is: " + curr_min + ":" + curr_sec+ ":" + curr_mil);
recursiveCall();
}
function recursiveCall(){
if(file_array.length > 0){
var string = file_array.pop();
setTimeout(function(){$.getScript(string,recursiveCall);},1);
}
else{
var d = new Date();
var curr_min = d.getMinutes();
var curr_sec = d.getSeconds();
var curr_mil = d.getMilliseconds();
console.log("test.js stopped background loading, time is: " + curr_min + ":" + curr_sec+ ":" + curr_mil);
}
}
這樣做是按順序處理文件數組,文件之間間隔1ms。 這有助於防止瀏覽器在加載過程中被完全鎖定,但瀏覽器仍然會因加載數據而陷入困境。 我正在加載的每個文件都是這樣的:
AddToBookData(0,[0,1,2,3,4,5,6,7,8]);
AddToBookData(1,[0,1,2,3,4,5,6,7,8]);
AddToBookData(2,[0,1,2,3,4,5,6,7,8]);
其中每一行都是一個將數據添加到數組的函數調用。 “AddToBookData”函數只執行以下操作:
function AddToBookData(index1,value1){
BookData[BookIndex].push([index1,value1]);
}
這是現有系統。 加載所有數據后,“AddToBookData”可以被調用100,000次以上。
我認為這是非常低效的,所以我編寫了一個腳本來獲取包含上面所有函數調用的test.js文件,並對其進行處理以將其更改為一個巨大的數組,該數組等於BookData正在創建的數據結構。 我沒有進行舊系統所做的所有函數調用,而只是執行以下操作:
var test_array[..........(data structure I need).......]
BookData[BookIndex] = test_array;
我期望看到性能提高,因為我正在刪除上面的所有函數調用,此方法需要稍多的時間來創建確切的數據結構。 我應該注意到“test_array”在我的真實世界測試中擁有略多於90,000個元素。
似乎兩種加載數據的方法都具有大致相同的CPU利用率。 我很驚訝地發現這一點,因為我希望第二種方法需要很少的CPU時間,因為數據結構是在手工創建的。
請指教?
看起來優化數據加載有兩個基本區域,可以單獨考慮和解決:
但我不確定你能夠在多大程度上優化單獨的數據加載。 要解決您的應用程序的實際問題(瀏覽器鎖定時間過長)您是否考慮過諸如?
所有目標瀏覽器可能都不支持Web Workers ,但應防止主瀏覽器線程在處理數據時鎖定。
對於沒有worker的瀏覽器,您可以考慮稍微增加setTimeout
間隔,以便為瀏覽器提供服務用戶和JS的時間。 這將使事情實際上稍微慢一點,但與下一點結合使用可能會增加用戶的快樂。
對於具有工作能力和缺少工作負載的瀏覽器,請花一些時間使用進度條更新DOM。 你知道有多少文件要加載,所以進度應該相當一致,雖然事情可能實際上稍慢,但如果用戶得到反饋並且不認為瀏覽器已經鎖定它們, 用戶會感覺更好 。
正如jira在他的評論中所建議的那樣。 如果Google Instant可以在我們輸入時搜索整個網絡,是否真的無法讓服務器返回包含當前圖書中所有搜索關鍵字位置的文件? 這個文件應該比書中所有單詞的位置小得多,加載速度要快得多,這就是我假設你正在嘗試盡可能快地加載?
我測試了三種將相同的9,000,000點數據集加載到Firefox 3.64中的方法。
1: Stephen's GetJSON Method
2) My function based push method
3) My pre-processed array appending method:
我以兩種方式運行測試:第一次測試迭代我導入了包含10,000行數據的100個文件,每行包含9個數據元素[0,1,2,3,4,5,6,7,8]
第二次交互我嘗試組合文件,以便我導入1個文件,包含900萬個數據點。
這比我將要使用的數據集大很多,但它有助於演示各種導入方法的速度。
Separate files: Combined file:
JSON: 34 seconds 34
FUNC-BASED: 17.5 24
ARRAY-BASED: 23 46
有趣的結果,至少可以說。 我在加載每個網頁后關閉了瀏覽器,並分別運行了4次測試,以最大限度地減少網絡流量/變化的影響。 (使用文件服務器在網絡上運行)。 您看到的數字是平均值,盡管個體運行最多只有一兩秒鍾。
不要使用$.getScript
來加載包含函數調用的JavaScript文件,而應考慮使用$.getJSON
。 這可能會提高性能。 這些文件現在看起來像這樣:
{
"key" : 0,
"values" : [0,1,2,3,4,5,6,7,8]
}
收到JSON響應后,您可以在其上調用AddToBookData
,如下所示:
function AddToBookData(json) {
BookData[BookIndex].push([json.key,json.values]);
}
如果您的文件有多組AddToBookData調用,您可以像這樣構造它們:
[
{
"key" : 0,
"values" : [0,1,2,3,4,5,6,7,8]
},
{
"key" : 1,
"values" : [0,1,2,3,4,5,6,7,8]
},
{
"key" : 2,
"values" : [0,1,2,3,4,5,6,7,8]
}
]
然后更改AddToBookData
函數以補償新結構:
function AddToBookData(json) {
$.each(json, function(index, data) {
BookData[BookIndex].push([data.key,data.values]);
});
}
附錄
我懷疑無論使用什么方法將數據從文件傳輸到BookData
數組,真正的瓶頸在於絕對數量的請求。 文件必須分成40-100嗎? 如果更改為JSON格式,則可以加載單個文件,如下所示:
{
"file1" : [
{
"key" : 0,
"values" : [0,1,2,3,4,5,6,7,8]
},
// all the rest...
],
"file2" : [
{
"key" : 1,
"values" : [0,1,2,3,4,5,6,7,8]
},
// yadda yadda
]
}
然后,你可以做一個請求,加載所有你需要的數據,然后繼續前進......雖然瀏覽器可能最初鎖定(雖然也許不是 ),它可能會快得多這種方式。
如果您不熟悉,這是一個很好的JSON教程: http : //www.webmonkey.com/2010/02/get_started_with_json/
以字符串形式獲取所有數據,並使用split()
。 這是在Javascript中構建數組的最快方法。
有一篇非常類似的問題來自構建flickr搜索的人: http : //code.flickr.com/blog/2009/03/18/building-fast-client-side-searches/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.