将大量数据加载到内存中 – 最有效的方法吗?

我有一个基于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时间,因为数据结构是在手工创建的。

请指教?

看起来优化数据加载有两个基本区域,可以单独考虑和解决:

  1. 从服务器下载数据 。 您应该从多个较小文件的并行加载中获得胜利,而不是一个大文件。 尝试同时加载的数量,牢记浏览器限制和太多并行连接的收益递减。 请参阅我在jsfiddle上的并行与顺序实验,但请记住,由于从github中提取测试数据的变幻莫测,结果会有所不同 – 您最好在更严格控制的情况下使用自己的数据进行测试。
  2. 尽可能高效地构建数据结构 。 你的结果看起来像一个多维数组, 这篇关于JavaScript数组性能的有趣文章可能会给你一些关于这方面实验的想法。

但我不确定你能够在多大程度上优化单独的数据加载。 要解决应用程序的实际问题(浏览器锁定时间过长),您是否考虑过诸如?

使用Web Workers

所有目标浏览器可能都不支持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/

以字符串forms获取所有数据,并使用split() 。 这是在Javascript中构建数组的最快方法。

有一篇非常类似的问题来自构建flickr搜索的人: http : //code.flickr.com/blog/2009/03/18/building-fast-client-side-searches/