Подтвердить что ты не робот

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

У меня есть веб-система поиска/просмотра документации, которую я разрабатываю для клиента. Часть этой системы - это поисковая система, которая позволяет клиенту искать термин [s], содержащийся в документации. У меня есть необходимые файлы данных поиска, но есть много данных, которые необходимо загрузить, и для загрузки всех данных требуется от 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 раз.

Я понял, что это было довольно неэффективно, поэтому я написал script, чтобы взять файл test.js, который содержит все вызовы функций выше, и обработал его, чтобы изменить его на гигантский массив, который равен структуре данных, которая BookData создает. Вместо выполнения всех вызовов функций, которые выполняла старая система, я просто делаю следующее:

var test_array[..........(data structure I need).......]
BookData[BookIndex] = test_array;

Я ожидал увидеть увеличение производительности, потому что я удалял все вызовы функций выше, этот метод занимает немного больше времени для создания точной структуры данных. Я должен отметить, что "test_array" содержит чуть более 90 000 элементов в моем реальном мире.

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

Просьба сообщить?

4b9b3361

Ответ 1

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

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

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

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

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

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

Предоставление отзывов о прогрессе

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

Lazy Loading

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

Ответ 2

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

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

Я провел тесты двумя способами: первая итерация тестирования я импортировал 100 файлов, содержащих 10 000 строк данных, каждая строка содержит 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

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

Ответ 3

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

Затем вы можете сделать один запрос, загрузить все необходимые вам данные и перейти... Хотя браузер может сначала заблокировать (хотя, может быть, и нет), он, вероятно, будет MUCH быстрее таким образом.

Вот хороший учебник JSON, если вы не знакомы: http://www.webmonkey.com/2010/02/get_started_with_json/

Ответ 4

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

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