Загрузка большого объема данных в память - самый эффективный способ сделать это? - PullRequest
20 голосов
/ 11 ноября 2010

У меня есть система поиска и просмотра документации на основе Интернета, которую я разрабатываю для клиента.Частью этой системы является поисковая система, которая позволяет клиенту искать термин (и), содержащийся в документации.У меня созданы необходимые файлы поисковых данных, но нужно загрузить много данных, и загрузка всех данных занимает от 8 до 20 секунд.Данные разбиты на 40-100 файлов, в зависимости от того, какую документацию нужно искать.Каждый файл имеет размер от 40 до 350 КБ.

Кроме того, это приложение должно быть в состоянии работать как в локальной файловой системе, так и через веб-сервер.

Когда веб-страница загружается, я могу создать список файлов с данными поиска, которые мне нужно загрузить.Весь этот список должен быть загружен, прежде чем веб-страницу можно будет считать работоспособной.

Учитывая это предисловие, давайте посмотрим, как я это делаю сейчас.

После того, как я узнаю, чтозагружается вся веб-страница, я вызываю функцию 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);
    }
  }

Это последовательно обрабатывает массив файлов с интервалом в 1 мс между файлами.Это помогает предотвратить полную блокировку браузера во время процесса загрузки, но браузер все еще имеет тенденцию зависать при загрузке данных.Каждый из загружаемых файлов выглядит следующим образом:

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 элементов.

Кажется, что оба метода загрузки данных имеют примерно одинаковую загрузку ЦП.Я был удивлен, обнаружив это, поскольку ожидал, что второй метод потребует небольшого процессорного времени, так как структура данных создается заранее.

Пожалуйста, посоветуйте?

Ответы [ 4 ]

15 голосов
/ 12 ноября 2010

Похоже, есть две основные области для оптимизации загрузки данных, которые можно рассматривать и решать отдельно:

  1. Загрузка данных с сервера .Вместо одного большого файла вы должны выиграть от параллельной загрузки нескольких меньших файлов.Поэкспериментируйте с количеством одновременных загрузок, имейте в виду ограничения браузера и уменьшение отдачи от слишком большого количества параллельных соединений.См. Мои параллельные против последовательных экспериментов на jsfiddle, но имейте в виду, что результаты будут отличаться из-за капризов извлечения тестовых данных из github - лучше всего тестировать самостоятельноданные в более жестких условиях.
  2. Построение структуры данных максимально эффективно .Ваш результат выглядит как многомерный массив, эта интересная статья о производительности массива JavaScript может дать вам некоторые идеи для экспериментов в этой области.

Но я не уверен, какпока вы действительно сможете оптимизировать загрузку данных в одиночку.Чтобы решить реальную проблему с вашим приложением (браузер заблокирован слишком долго), вы рассматривали варианты, такие как?

Использование веб-работников

Веб-работники могут не поддерживатьсявсеми вашими целевыми браузерами, но должны предотвращать блокировку основного потока браузера во время обработки данных.

Для браузеров без работников вы можете немного увеличить интервал setTimeout, чтобы дать браузеру время на обслуживаниепользователь, а также ваш JS.Это на самом деле сделает все немного медленнее, но может увеличить радость пользователя в сочетании со следующей точкой.

Обеспечение обратной связи о прогрессе

Для браузеров как с рабочими возможностями, так и с ограниченными рабочими, потратьте некоторое время наобновить DOM с помощью индикатора выполнения.Вы знаете, сколько файлов осталось загрузить, поэтому прогресс должен быть достаточно последовательным, и хотя на самом деле все может быть немного медленнее, пользователи будут чувствовать себя лучше , если они получат обратную связь и не думают, что браузер заблокированна них.

Ленивая загрузка

Как подсказывает jira в своем комментарии.Если Google Instant может выполнять поиск по всей сети по мере ввода, действительно ли невозможно, чтобы сервер возвращал файл со всеми местоположениями поискового ключевого слова в текущей книге?Этот файл должен быть намного меньше и быстрее загружаться, чем расположение всех слов в книге, что, как я полагаю, вы сейчас пытаетесь загрузить как можно быстрее?

4 голосов
/ 12 ноября 2010

Я проверил три метода загрузки одного и того же набора данных из 9 000 000 точек в Firefox 3.64.

1: Stephen's GetJSON Method
2) My function based push method
3) My pre-processed array appending method:

Я провел свои тесты двумя способами: В первой итерации я импортировал 100 файлов, содержащих 10000 строк данных, каждыйстрока, содержащая 9 элементов данных [0,1,2,3,4,5,6,7,8]

Во втором случае я попытался объединить файлы, чтобы импортировать 1 файл с 9 миллионами точек данных.

Это было намного больше, чем набор данных, который я буду использовать, но это помогает продемонстрировать скорость различных методов импорта.

Separate files:                 Combined file:

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

Интересные результаты, если не сказать больше.Я закрыл браузер после загрузки каждой веб-страницы и запускал тесты по 4 раза каждый, чтобы минимизировать влияние сетевого трафика / вариаций.(бегал по сети, используя файловый сервер).Число, которое вы видите, является средним, хотя отдельные пробеги отличались не более чем на секунду или две.

0 голосов
/ 12 ноября 2010

Получить все данные в виде строки и использовать split().Это самый быстрый способ создания массива в Javascript.

Есть отличная статья, очень похожая проблема, от людей, которые создали поиск по flickr: http://code.flickr.com/blog/2009/03/18/building-fast-client-side-searches/

0 голосов
/ 11 ноября 2010

Вместо использования $.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/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...