ПРОБЛЕМА: Я пытаюсь ускорить поиск в 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();
}
}
}
}
Любые идеи о том, как я могу это сделать, или другие предложения по значительному ускорению поиска?
Вы можете заменить Promise.race()
на Promise.all()
чтобы вернуть разрешенное Promise
как только будет найдено совпадение, вместо того, чтобы ждать, пока все Promise
переданные Promise.all()
будут разрешены.
Promise.race()
и отметьте различия в тестах, если таковые имеются. В настоящее времяjavascript
в Question, кажется, ожидает выполнения всех объектовPromise
переданных вPromise.all()
вместо вызова.then()
когда любое из значенийPromise
разрешено. Помимо этой корректировки, если алгоритм поиска в настоящее время выполняет необходимую задачу, не знаете, как можно улучшить поиск, если вы пришли к выводу, что создание большегоWebWorker
экземпляровWebWorker
не уменьшает общее время процедуры?