Сага о скорости sscanf

В нашем проекте есть одно из мест при чтении, когда надо распарсить строчку с числами вида «{ 123, 234, 345, 456, 567 }». Там всегда стоял сишный код декодирования через scanf. Ну а потом там пришлось все переделывать, и я на автомате написал декодирование в Qt стиле. А потом решил проверить что же будет быстрее.

Итого, у нас 2 варианта:
1) Ищем каждую первую цифру из каждого из чисел, после чего натравливаем scanf()
2) Сплитим строчку по разделителю, после чего для каждой полученной строки исполняем QString().toInt()

Для проверки что же работает быстрее я написал следующий код:

#include <QCoreApplication>
#include <QtGlobal>

#include <QElapsedTimer>
#include <QString>
#include <QStringList>
#include <QDebug>

#include <stdio.h>

int main(int argc, char *argv[])
{
    QByteArray r;
    for (int i = 0; i < 1000000; i++) {
        float a;
        int b = rand();
        a = *reinterpret_cast<float*>(&b);
        r += QString::number(rand()).toUtf8() + '\0';
    }

    //------------------------------------------
    //------------------------------------------

    QElapsedTimer timer;
    timer.start();

    QList<QByteArray> l = r.split('\0');
    float res = 0;
    for (int i = 0; i < l.size(); i++) {
        res += l.at(i).toFloat();
    }

    qDebug() << res << timer.elapsed();

    //------------------------------------------

    timer.start();

    const char *data = r.data();
    int size = r.size() - 1;
    res = 0;
    float f;
    for (int i = 0; i < size; i++)
        if (data[i] == '\0') {
            sscanf(data + i + 1, "%f", &f);
            res += f;
        }

    qDebug() << res << timer.elapsed();

    return 0;
}

Дебаг сборка
Qt: 165мс на декодирование
Си: 171мс на декодирование

Релиз сборка
Qt: 144мс
Си: 153мс

Массив чисел можно генерить как из целых, так и из float — скорость от этого особо не изменится. Зато скорость знатно меняется, если в качестве разделителя использовать не \0, а, допустим, просто пробел.

В таком случае, если уменьшить количество чисел с 1000000 до 100000, скорости будут такими (релиз):
Qt: 18мс
Си: 963мс

Знаете что это значит? Это значит, что если втупую написать код на Си, ожидая что он будет работать быстрее, то он не только может оказаться медленнее, он может совершенно случайно начать работать за квадрат вместо линии, которую обеспечивает Qt. Остается только догадываться насколько эффективно можно использовать еще более быстрый инструмент — ассемблер.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *