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

时间:2010-11-11 18:50:12

标签: javascript jquery data-structures

我有一个基于网络的文档搜索/查看系统,我正在为客户开发。该系统的一部分是一个搜索系统,允许客户端搜索文档中包含的术语[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时间,因为数据结构是在手工创建的。

请指教?

4 个答案:

答案 0 :(得分:15)

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

  1. 从服务器下载数据。您应该从多个较小文件的并行加载中获得胜利,而不是一个大文件。尝试同时加载的数量,牢记浏览器限制和太多并行连接的收益递减。请参阅我在jsfiddle上的parallel vs sequential实验,但请记住,由于从github提取测试数据的变幻莫测,结果会有所不同 - 您最好在更紧密的情况下使用自己的数据进行测试受控条件。
  2. 尽可能高效地构建数据结构。您的结果看起来像一个多维数组,this interesting article关于JavaScript数组的性能可能会为您提供一些实验的想法。
  3. 但是我不确定你能够在多大程度上优化单独的数据加载。要解决应用程序的实际问题(浏览器锁定时间过长),您是否考虑过选项,例如?

    使用Web Workers

    所有目标浏览器可能都不支持

    Web Workers,但应防止主浏览器线程在处理数据时锁定。

    对于没有工作人员的浏览器,您可以考虑稍微增加setTimeout间隔,以便为浏览器提供服务用户和JS的时间。这会使事情实际上稍微慢一点,但与下一点结合使用可能会增加用户的快乐。

    提供进展反馈

    对于具有工作能力和工作人员不足的浏览器,请花一些时间使用进度条更新DOM。你知道你还有多少文件要加载,所以进度应该相当一致,虽然事情实际上可能稍慢,users will feel better如果得到反馈并且不认为浏览器已锁定它们。

    延迟加载

    正如jira在评论中所建议的那样。如果Google Instant可以在我们输入时搜索整个网络,是否真的无法让服务器返回包含当前图书中所有搜索关键字位置的文件?这个文件应该比书中所有单词的位置小得多,加载速度要快得多,这就是我假设你现在正试图尽快加载?

答案 1 :(得分:4)

我测试了三种将相同的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]

我尝试组合文件的第二次交互,因此我导入了一个包含900万个数据点的文件。

这比我将要使用的数据集大很多,但它有助于演示各种导入方法的速度。

Separate files:                 Combined file:

JSON:        34 seconds         34
FUNC-BASED:  17.5               24
ARRAY-BASED: 23                 46

有趣的结果,至少可以说。我在加载每个网页后关闭了浏览器,并分别运行了4次测试,以最大限度地减少网络流量/变化的影响。 (使用文件服务器在网络上运行)。您看到的数字是平均数,尽管个体运行最多只有一两秒钟。

答案 2 :(得分:0)

不要使用$.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/

答案 3 :(得分:0)

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

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