Search
Write a publication
Pull to refresh
31
0
Григорий Кошелев @gnkoshelev

Team Lead

Send message
Верное замечание, спасибо.

Такой исходный код:
        switch(s) {
            case "s":
                System.out.println("S");
                break;
            case "b":
                System.out.println("B");
                break;
        }

компилируется в
        int var_ = -1;
        switch(s.hashCode()) {
        case 98:
            if(s.equals("b")) {
                var_ = 1;
            }
            break;
        case 115:
            if(s.equals("s")) {
                var_ = 0;
            }
        }

        switch(var_) {
        case 0:
            System.out.println("S");
            break;
        case 1:
            System.out.println("B");
        }
На assert явным образом есть отсылка в авторском разборе:
Вадим же человек аккуратный (вы посмотрите, сколько assertов!), значит, комментарий к методу он тоже написал аккуратно, а там указано, что метод вернет число в интервале от 0 до partitions исключительно.

У читателей может сложиться ложное впечатление, что это best practice, не так ли?

А вот тут
Другая, более серьезная проблема Вадима гораздо менее очевидна. Способ, который он выбрал, чтобы распределять данные по серверам, неконсистентен: при изменении количества партиций (например, при добавлении серверов) все треки перераспределяются по кластеру практически полностью.

ничего нет про поведение Object.hashCode(), а именно про его невоспроизводимость. Последнее, опять же на мой взгляд, куда большая проблема, чем изменение количество шардов, т.к. их количество может измениться либо вследствие сбоев, либо намеренного изменения (см. отсылки к Elasticsearch или MongoDB), в то время как hashCode на разных серверах для одних и тех же объектов уже будет давать разные результаты. Это важно.
Строго говоря, ни одна из спецификаций (JLS, JVMS) это не гарантирует. Соглашусь с тем, что на практике проблема скорее всего надуманная.
А может вы знаете лучшие решения? Добро пожаловать в комменты!

Вызов принят! Лучшие-нелучшие, но есть, что обсуждать. :)

Спасибо!
Надо будет поизучать этот вопрос. Неспроста же есть ключик -XX:UseAVX...

Электронные книги тоже теперь дарят? :)
К тому же много кто предпочитает бумажные книги.
Попробовал проверить, что делает JIT-компилятор в случае использования int — никаких намёков на оптимизацию.

Попробовал ещё в SIMD (независимые вычисления, простые циклы) — тоже безрезультатно.

Вывод: либо JIT-компилятор в это не умеет, либо я неправильно его готовлю.
Первая книга выпускалась издательством со своими заморочками по цензуре, редактуре. Плюс ко всему прочему — издательство получает определённые права на книгу, например, её нельзя будет просто так взять и переиздать в другом издательстве или опубликовать в свободный доступ (Milfgard об этом как раз писал либо в постах по ссылкам выше, либо в комментариях к этим же статьям).

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

В компании же есть хорошие дизайнеры, которые смогут самостоятельно сверстать книгу?

А печать уже делать в типографии. Был опыт издания книг небольшим тиражом в Екатеринбурге (за отдельную плату можно получить ISBN) — могу рассказать, как это происходит.
Отправил соответствующий баг в Oracle по странному различию в производительности по сути идентичного кода (см. FinalOrNotFinalBenchmark). Сегодня подтвердили баг: JDK-8200412.

Android — это вообще отдельный мир со своим байткодом и VM (Dalvik / ART) со своим JIT'ом.

Нет. В Java вычисления с плавающей точкой реализованы в соответствии со стандартом IEEE 754. Это явно указано в javadoc к java.lang.StrictMath.


Напротив, --ffast-math допускает использование оптимизаций, нарушающих указанный стандарт.

В какую именно? Заменять a * a * ... * a, как это сделано в примере? Так это не совсем законно (нарушает лево-ассоциативность операции умножения).

Java умеет в JNI, а вызываемый модуль можно и на асме написать, главное, что бы выигрыш был больше, чем накладные расходы на вызов этой функции.

Насколько дорого ходить в JNI — можно прикинуть, если сравнить бенчмарки с интринсиком и без (последний бенчмарк).

В общем случае, когда операнды типа float/double, FPU прекрасно посчитает x^y как 2^(y*log(x)) (при условии, что x > 0). Правда, FYL2X (y*log(x)) раз в 20-40 дороже умножения/деления в зависимости от архитектуры. Но выигрыш будет заметен на больших степенях.
Насколько мне известно, цепочка получается подлиннее (даже без учёта перекомпиляции из C1 в C2): java -> bytecode -> IR -> native code (~ машинные коды).

И еще одно — лобовая реализация описанного в ассемблере скорее всего будет эффективнее

В конкретном примере из статьи (и во многих других) — да. Но не стоит недооценивать умение JIT-компилятора учитывать собираемый профиль (= учитывать реальное исполнение кода, реальные данные в нашем приложении).
К сожалению, у меня нет под рукой этой книги, но готов поспорить, что там нет ничего про интринсики в Java, как и нет информации о том, как реализовано возведение в степень в HotSpot 7 / 8 / 9.

Впрочем, всё это не отменяет того факта, что
в 90% случаев достаточно использовать подходящие структуры данных и алгоритмы.
Видимо, принцип «скомпилируй, посмотри сгенерированный код» до сих пор актуален.
И ещё мини вывод: знание ассемблера нужно.

Это в полной мере справедливо для C++, т.к. AOT-компилятор. С Java всё намного сложнее, т.к. в JIT-компиляторе огромное количество оптимизаций, а их применение зависит от собранного профиля. Последнее означает, что результат JIT-компиляции может отличаться не только между кодом реального приложения и бенчмарка, так и в разные запуски приложения, да даже в разные моменты времени в одном запущенном приложении.

Пример:
В некотором коде может произойти NullPointerException, но в течение сбора профиля оно ни разу не случалось, поэтому JIT-компилятор C2 скомпилировал только так называемый common case — код, который исполняется часто, а остальную часть кода (обработка NPE в данном случае) не скомпилировал вовсе, оставив так называемую uncommon trap. Если в какой-то момент возникнет NullPointerException, то HotSpot вынужден будет откатиться в режим интерпретатора для этого участка кода, а в результате получить деоптимизацию всего метода. Когда JIT-компилятор вновь решится компилировать код и как он это сделает — предсказать мне невозможно.
Кажется, что в 90% случаев достаточно использовать подходящие структуры данных и алгоритмы. В связи с чем могу порекомендовать книги Лафоре (Структуры данных и алгоритмы в Java) и Седжвика (Алгоритмы на Java).
Ещё в 9% случаев нужно копать в сторону эффективности используемых фреймворков и тулкитов.
Оставшийся 1% бизнесу, как правило, не интересен.

Конечно, всё зависит от задач. Но если брать среднюю температуру по больнице, предположение выше не так уж далеко от истины.

Information

Rating
Does not participate
Location
Екатеринбург, Свердловская обл., Россия
Works in
Registered
Activity