Почему преобразование формата даты медленнее с буферами, чем со строковыми операциями? - PullRequest
0 голосов
/ 18 апреля 2019

Рассмотрим этот код:

    //Buffers and views
    function convertDateTimeToFormat(date, format) {
        var buf = new ArrayBuffer(14);
        var result = new Uint8Array(buf);
        var positions = {
            y: 0,
            M: 4,
            d: 6,
            H: 8,
            m: 10,
            s: 12
        };
        for (var index = 0; index < 14; index++) {
            result[index] = date[positions[format[index]]++];
        }
        return result;
    }
var dt = new Date();
for (var i = 0; i < 100000; i++) {
    var results = {};
    //2019-03-01 13:03:50
    var buf = new ArrayBuffer( 14 );
    buf[0] = 2;
    buf[1] = 0;
    buf[2] = 1;
    buf[3] = 9;
    buf[4] = 0;
    buf[5] = 3;
    buf[6] = 0;
    buf[7] = 1;
    buf[8] = 1;
    buf[9] = 3;
    buf[10] = 0;
    buf[11] = 3
    buf[12] = 5;
    buf[13] = 0;
    convertDateTimeToFormat(buf, "MMddyyyyHHmmss");
}
var dt2 = new Date();
console.log(dt2 - dt);
console.log(convertDateTimeToFormat(buf, "yyyyMMddHHmmss"));
console.log(convertDateTimeToFormat(buf, "MMddyyyyHHmmss"));

Время, необходимое для 10 экспериментов, было:

200, 184, 195, 186, 197, 193, 198, 197,211, 202

В среднем: 196.3

Я пробовал это и с операциями со строками:

function convertDateTimeToFormat(date, format) {
    var result = "";
    var positions = {
        y: 0,
        M: 4,
        d: 6,
        H: 8,
        m: 10,
        s: 12
    };
    for (var index = 0; index < 14; index++) {
        result += date[positions[format[index]]++];
    }
    return result;
}
var dt = new Date();
for (var i = 0; i <100000; i++) {
    var source = "20190301130350";
    convertDateTimeToFormat(source, "MMddyyyyHHmmss");
}
var dt2 = new Date();
console.log(dt2 - dt);
console.log(convertDateTimeToFormat(source, "yyyyMMddHHmmss"));
console.log(convertDateTimeToFormat(source, "MMddyyyyHHmmss"));

Тем не менее,необходимые времена:

70, 72, 61, 61, 65, 72, 60, 61, 72, 68

В среднем: 66.2

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

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Вы все еще используете ArrayBuffer неправильно .Это var buf = new ArrayBuffer( 14 ); используется так же, как если бы вы написали var buf = {}; - вы создаете свойства для него, как и для любого обычного объекта, и это медленно.

Вместо этого вы должны сделать

var buf = [];

или

var buf = new Uint8Array(14);

Тем не менее:

Операции со строками имеют тенденцию быть медленными.

Нет.Строковые операции сильно оптимизированы движками JS, даже повторяющиеся операции += в цикле.И строки создавать относительно дешево.

С другой стороны, типизированные массивы и буферы массивов имеют довольно много накладных расходов при их создании.Они могут быть быстрыми для доступа, но ваш простой тест не использует их так часто - только устанавливает и читает и устанавливает каждый из 14 индексов, но создает два ArrayBuffer и два Uint8Array экземпляра.

1 голос
/ 18 апреля 2019

Ваши тесты не измеряют так же, как в первом тесте вы тратите время на создание нового ArrayBuffer, а во втором тесте строка «уже определена в памяти», поэтому она дешевле.

Iсоздали тест с разными числами даты (рандомизированными), создали буфер и строку для тех же чисел ДО запуска таймера.Струны еще быстрее, но меньше.Это результат:

enter image description here

var SIZE = 100000;
var dates = [];
for (var i = 0; i < SIZE; i++) {
    var buf = new ArrayBuffer(14);
    var str = "";
    buf[0] = Math.floor(Math.random()*10);
    buf[1] = Math.floor(Math.random()*10);
    buf[2] = Math.floor(Math.random()*10);
    buf[3] = Math.floor(Math.random()*10);
    buf[4] = Math.floor(Math.random()*10);
    buf[5] = Math.floor(Math.random()*10);
    buf[6] = Math.floor(Math.random()*10);
    buf[7] = Math.floor(Math.random()*10);
    buf[8] = Math.floor(Math.random()*10);
    buf[9] = Math.floor(Math.random()*10);
    buf[10] = Math.floor(Math.random()*10);
    buf[11] = Math.floor(Math.random()*10);
    buf[12] = Math.floor(Math.random()*10);
    buf[13] = Math.floor(Math.random()*10);
    for (var ii = 0; ii < 14; ii++) {
        str += buf[ii];
    }
    dates.push({buf, str});
}

function convertDateTimeToFormatBuf(date, format) {
    var buf = new ArrayBuffer(14);
    var result = new Uint8Array(buf);
    var positions = {
        y: 0,
        M: 4,
        d: 6,
        H: 8,
        m: 10,
        s: 12
    };
    for (var index = 0; index < 14; index++) {
        result[index] = date[positions[format[index]]++];
    }
    return result;
}
function convertDateTimeToFormatStr(date, format) {
    var result = "";
    var positions = {
        y: 0,
        M: 4,
        d: 6,
        H: 8,
        m: 10,
        s: 12
    };
    for (var index = 0; index < 14; index++) {
        result += date[positions[format[index]]++];
    }
    return result;
}

console.time("Buffer");
for (i = 0; i < SIZE; i++) {
    convertDateTimeToFormatBuf(dates[i].buf, "MMddyyyyHHmmss");
}
console.timeEnd("Buffer");

console.time("String");
for (i = 0; i < SIZE; i++) {
    convertDateTimeToFormatStr(dates[i].str, "MMddyyyyHHmmss");
}
console.timeEnd("String");

V8 значительно оптимизирован при объединении строк.У вас есть фиксированный цикл с простой конкатенацией строк, поэтому V8 оптимизирует его довольно хорошо, поскольку он знает, что на самом деле происходит внутри цикла.Я предполагаю, что конкатенация строк в памяти не произойдет, пока цикл не завершится, что будет довольно быстро.

С буферами все по-другому.Вы ничего не объединяете, так как вы просто получаете доступ к позициям памяти (хотя вы делаете это последовательно), но ожидайте, что при каждой позиции, которую вы устанавливаете, запись в память происходит мгновенно (без какой-либо оптимизации).Все это с накладными расходами, которые означают запись в массив uint8.

Типизированные массивы предполагают, что к памяти осуществляется прямой доступ, как это происходит в C и т. П., Но в типизированных JavaScript-массивах издержки намного больше, чем в строке, как вы можетечитайте здесь: https://stackoverflow.com/a/45808835/1525495

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