Паранойя производительности: насколько дороги Float.parseFloat (String), Integer.parseInt (String)? - PullRequest
4 голосов
/ 05 апреля 2011

Я недавно использую JSON для хранения параметров конфигурации для определенного количества подклассов одного и того же класса. Чтобы сохранить единый интерфейс, я предоставил родительскому классу открытые методы void setParameter(String, String) и String getParameter(String). Каждый подкласс затем преобразует предоставленные параметры в их собственный тип и выполняет какие-то вычисления, используя их.

Теперь мне интересно: поскольку я уже храню каждый параметр в HashMap, имеет ли смысл сохранять отдельное поле с правильным типом для каждого параметра? Каковы вычислительные затраты на преобразование параметров String в их собственный тип каждый раз, когда они мне нужны, учитывая, что мне нужно использовать их очень часто?

Спасибо.
Tunnuz

Ответы [ 3 ]

5 голосов
/ 05 апреля 2011

Я предлагаю вам проверить это.Это довольно дорогая операция, если вам нужно делать это много, много раз, но она может быть дешевле, чем Double.toString () или Integer.toString (), если вы использовали их для создания данных.

Я также предлагаю вам использовать только double, если только вы не знаете, что использование float никогда не вызовет проблемы с округлением.;)

Это примерно так же дорого, как создание объектов, таких как String или добавление записи в HashMap.Если вы не планируете этого делать, я бы об этом не беспокоился.

РЕДАКТИРОВАТЬ: аналогично тесту @Stackers, я бы запустил тест дольше и использовал бы nanoTime ()

int runs = 10000000;
String val = "" + Math.PI;
long start = System.nanoTime();
for (int i = 0; i < runs; i++)
    Float.parseFloat(val);
long time = (System.nanoTime() - start) / runs;
System.out.println("Average Float.parseFloat() time was " + time + " ns.");

long start2 = System.nanoTime();
for (int i = 0; i < runs; i++)
    Double.parseDouble(val);
long time2 = (System.nanoTime() - start2) / runs;
System.out.println("Average Double.parseDouble() time was " + time2 + " ns.");

print

Average Float.parseFloat() time was 474 ns.
Average Double.parseDouble() time was 431 ns.

Кстати: у меня есть функциячитает удваивается от прямого ByteBuffer, который занимает 80 нс.Это быстрее, потому что ему не нужна строка и он не создает никаких объектов.Однако сделать это отнюдь не тривиально, и вы должны спроектировать основную систему, чтобы избежать создания каких-либо объектов.;)

3 голосов
/ 05 апреля 2011

, хотя микробенчмарки, показанные выше, кажутся немного небезопасными, можно ожидать, что горячая точка обнаружит, что val никогда не меняется и никогда не используется. Еще одна вещь, которую нужно иметь в виду, это то, что бывают случаи, когда средние значения (из 2 реализаций) могут быть близки друг к другу в абсолютном выражении, но когда 1 имеет довольно плохую хвостовую стоимость по сравнению с другим, например, Ваше значение 90-го процентиля может быть очень похоже, но последние 10% намного хуже.

Например, изменение его для использования другого значения каждый раз и выгрузка значения в stderr приводит к несколько более высокой средней стоимости (~ 3300 нс против ~ 2500 нс для случая, когда значение используется повторно) на моем ящике. Это намного выше, чем у других постов, по-видимому, потому что требуется некоторое время, чтобы фактически получить время, чтобы измерение было искусственно завышено. Это только показывает одну из трудностей в создании хорошего микробенчмарка.

Стоит также отметить, что я не могу измерить тот эффект, который я предложил, например, присутствовать. если он присутствует, то вы можете ожидать, что он будет полностью оптимизирован. Я полагаю, вы могли бы видеть, что происходит через LogCompilation, если вы действительно заинтересованы.

    int runs = 10000000;
    long totalTime = 0;
    for (int i = 0; i < runs; i++) {
        String val = "" + Math.random();
        long start = System.nanoTime();
        float f = Float.parseFloat(val);
        long end = System.nanoTime();
        System.err.println(f);
        totalTime += (end-start);
    }
    long time = totalTime / runs;
    totalTime = 0;
    for (int i = 0; i < runs; i++) {
        String val = "" + Math.random();
        long start = System.nanoTime();
        double d = Double.parseDouble(val);
        long end = System.nanoTime();
        System.err.println(d);
        totalTime += (end-start);
    }
    long time2 = totalTime / runs;
    System.out.println("Average Float.parseFloat() time was " + time + " ns.");
    System.out.println("Average Double.parseDouble() time was " + time2 + " ns.");
3 голосов
/ 05 апреля 2011

Измерение так же просто, как:

public class PerfTest {
    public static void main(String[] args) {
        String val = "" + (float) Math.PI;
        long start = System.currentTimeMillis();
        for ( int i = 0 ; i < 100000 ; i++ ) {
            Float.parseFloat( val );
        }
        System.out.println( System.currentTimeMillis() - start + " ms." );
    }
}

62мс для 100 000 итераций.

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