Ускорение поиска в IndexedDB с несколькими работниками

1

ПРОБЛЕМА: Я пытаюсь ускорить поиск в IndexedDB с помощью нескольких веб-работников и, следовательно, одновременно выполнять несколько транзакций чтения, но это не работает, и мой процессор загружается примерно на 30-35%. У меня 4-ядерный процессор, и я надеялся, что нерест 4 веб-работников значительно сократит время поиска.

Я использую Firefox 53 с WebExtension; другие браузеры не являются опцией.

БАЗЫ ДАННЫХ: У меня есть хранилище данных с около 250 000 записей, каждый из которых содержит около 30 ключей, некоторые из которых содержат абзацы текста.

TASK: выполнить поиск строк по заданному ключу, чтобы найти соответствующие значения. В настоящее время для одного потока требуется около 90 секунд. Добавление дополнительного рабочего сокращает время до примерно 75 секунд. Больше работников, чем это, не имеет заметного эффекта. Допустимое время для меня будет менее 10 секунд (несколько сопоставимо с базой данных SQL).

ТЕКУЩАЯ СТРАТЕГИЯ: Создайте рабочего для каждого процессора и создайте обещание, которое разрешает, когда рабочий отправляет сообщение. В каждом рабочем месте откройте базу данных, разделите записи равномерно и найдите строку. Я делаю это, начиная с первой записи, если вы первый рабочий, второй рекорд для второго и т.д. Затем продвигайтесь по количеству рабочих. Таким образом, первый работник проверяет записи 1, 5, 9 и т.д. Второй рабочий проверяет 2, 6, 10 и т.д. Конечно, я мог бы также иметь первую рабочую проверку 1-50, вторую проверку работника 51-100 и т.д. ( но, очевидно, тысячи каждый).

Использование getAll() в одном потоке заняло почти вдвое больше времени и 4 ГБ памяти. Разделение на 4 диапазона значительно сокращает время до примерно 40 секунд после слияния результатов (40 секунд каждый раз меняется каждый раз, когда я запускаю сценарий).

Любые идеи о том, как я могу это сделать, или другие предложения по значительному ускорению поиска?

background.js:

var key = whatever, val = something
var proc = navigator.hardwareConcurrency;  // Number of processors
var wPromise = [];  // Array of promises (one for each worker)
var workers = [];

/* Create a worker for each processor */
for (var pos = 0; pos < proc; pos++) {
    workers[pos] = new Worker("js/dbQuery.js");
    wPromise.push(
        new Promise( resolve => workers[pos].onmessage = resolve )
    );
    workers[pos].postMessage({key:key, val:val, pos:pos, proc:proc});
}

return Promise.all(wPromise);  // Do something once all the workers have finished

dbQuery.js:

onmessage = e => {
    var data = e.data;
    var req = indexedDB.open("Blah", 1);
    req.onsuccess = e => {
        var keyArr = [];
        var db = e.currentTarget.result;
        db.transaction("Blah").objectStore("Blah").index(data.key).openKeyCursor().onsuccess = e => {
            var cursor = e.target.result;
            if (cursor) {
                if (data.pos) {
                    cursor.advance(data.pos); // Start searching at a position based on which web worker
                    data.pos = false;
                }
                else {
                    if (cursor.key.includes(data.val)) {
                        keyArr.push(cursor.primaryKey);  // Store key if value is a match
                    }
                    cursor.advance(data.proc); // Advance position based on number of processors
                }
            }
            else {
                db.close();
                postMessage(keyArr);
                close();
            }
        }
    }
}
Теги:
performance
multithreading
indexeddb
web-worker

1 ответ

0

Любые идеи о том, как я могу это сделать, или другие предложения по значительному ускорению поиска?

Вы можете заменить Promise.race() на Promise.all() чтобы вернуть разрешенное Promise как только будет найдено совпадение, вместо того, чтобы ждать, пока все Promise переданные Promise.all() будут разрешены.

  • 0
    Я не совсем уверен, как это заставляет поиск работать быстрее. Основная проблема заключается в том, сколько времени требуется для получения окончательного соответствия, которое зависит от количества значений, которые я должен проверить для данного ключа.
  • 0
    @DanielH Смотрите "или другие предложения для значительного ускорения поиска". Попробуйте Promise.race() и отметьте различия в тестах, если таковые имеются. В настоящее время javascript в Question, кажется, ожидает выполнения всех объектов Promise переданных в Promise.all() вместо вызова .then() когда любое из значений Promise разрешено. Помимо этой корректировки, если алгоритм поиска в настоящее время выполняет необходимую задачу, не знаете, как можно улучшить поиск, если вы пришли к выводу, что создание большего WebWorker экземпляров WebWorker не уменьшает общее время процедуры?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню