JodaTime Хронология кэширования - PullRequest
2 голосов
/ 23 июня 2011

Я успешно написал новую хронологию, которая представляет финансовый календарь моей компании, основанный на JodaTime.Я немного упомянул исходный код JodaTime, чтобы понять, что мне нужно делать.Одной из вещей, которые я заметил в классе BasicChronology, было использование внутреннего класса YearInfo для кэширования 'firstDayOfYearMillis' - количество миллисекунд с 1970-01-01 (ISO).Подумав, что, если достаточно узкого места в производительности, которое кэширует JodaTime, я, вероятно, должен добавить его и в свою хронологию.
Однако, когда я сделал это, я внес некоторые изменения.В частности, я переместил метод getYearInfo во внутренний класс YearInfo, а также сделал его статическим.Я также переместил массив, используемый для хранения кэшированных значений, во внутренний класс.Полное определение измененного класса выглядит следующим образом:

/**
 * Caching class for first-day-of-year millis.
 *
 */
private static final class YearInfo {

    /**
     * Cache setup for first-day-of-year milliseconds.
     */
    private static final int CACHE_SIZE = 1 << 10;
    private static final int CACHE_MASK = CACHE_SIZE - 1;
    private static transient final YearInfo[] YEAR_INFO_CACHE = new YearInfo[CACHE_SIZE];

    /**
     * Storage variables for cache.
     */
    private final int year;
    private final long firstDayMillis;
    private final boolean isLeapYear;


    /**
     * Create the stored year information.
     * 
     * @param inYear The year to store info about.
     */
    private YearInfo(final int inYear) {
        this.firstDayMillis = calculateFirstDayOfYearMillis(inYear);
        this.isLeapYear = calculateLeapYear(inYear);
        this.year = inYear;
    }

    /**
     * Get year information.
     * 
     * @param year The given year.
     * 
     * @return Year information.
     */
    private static YearInfo getYearInfo(final int year) {
        YearInfo info = YEAR_INFO_CACHE[year & CACHE_MASK];
        if (info == null || info.year != year) {
            info = new YearInfo(year);
            YEAR_INFO_CACHE[year & CACHE_MASK] = info;
        }
        return info;
    }
}

У меня вопрос ... Каковы последствия моих изменений для производительности или дизайна?Я уже решил, что мои изменения должны быть поточно-ориентированными (учитывая ответы о конечных переменных-членах).Но почему оригинальная реализация была сделана такой, какой она была, а не такой?Я понимаю, почему большинство методов, которые эффективно используются статически, нет (с учетом подклассов BasicChronology), но я признаю, что некоторые из моих вещей в ОО-дизайне немного ржавые (последние два года я использовал RPG).
Итак ... мысли?

Ответы [ 2 ]

2 голосов
/ 01 августа 2011

Я написал оригинальный код, который кэшируется в объекты YearInfo. Ваше решение инкапсулировать больше логики в класс YearInfo прекрасно и должно работать так же хорошо. Я разработал YearInfo, основываясь на намерениях - я хотел получить сырую пару данных и больше ничего. Если бы Java поддерживал структуры, я бы использовал здесь.

Что касается самой конструкции кеша, то она основывалась на результатах профилирования, чтобы посмотреть, окажет ли это какое-либо влияние. В большинстве мест Joda-Time лениво вычисляет значения полей, и кэширование их для дальнейшего повышения производительности. Поскольку этот конкретный кэш имеет фиксированный размер, он не может пропускать память. Максимальный объем потребляемой памяти составляет 1024 объекта YearInfo, что составляет около 20 Кбайт.

Joda-Time полна специализированных кешей, подобных этой, и все они продемонстрировали ощутимое улучшение производительности. Я не могу сказать, насколько эффективны эти методы, поскольку они были написаны и протестированы на JDK 1.3.

2 голосов
/ 24 июня 2011

Что касается правильности, переключив YEAR_INFO_CACHE на статический, вы ввели небольшую утечку памяти. Есть несколько способов определить, имеют ли значение ваши статические ссылки на практике, например, сделайте приблизительную аппроксимацию того, насколько большой кэш будет расти на основе того, что вы знаете о данных; профилировать кучу во время / после нагрузочного теста вашего приложения; и т.д.

Вы кэшируете такие маленькие объекты, что, вероятно, многие из них могут быть кэшированы без проблем Тем не менее, если вы обнаружите, что кеш должен быть ограничен, у вас есть несколько вариантов, таких как кеш LRU, кеш, основанный на мягких ссылках, а не на прямых (сильных) ссылках и т. Д. Но еще раз подчеркну, что для вашего В конкретной ситуации реализация любого из этих может быть пустой тратой времени .

Чтобы объяснить теоретическую проблему со статическими ссылками, я буду ссылаться на другие сообщения, а не воспроизводить их здесь:
1. Открыты ли статические поля для сборки мусора?
2. Может ли использование слишком большого количества статических переменных вызвать утечку памяти в Java?

Также в отношении корректности код является поточно-ориентированным не потому, что ссылки являются окончательными, а потому, что значения YearInfo, созданные несколькими потоками для некоторой позиции в кэше, должны быть равными, поэтому не имеет значения, какой из них окажется в кэше.

Что касается дизайна, все связанные с YearInfo материалы в исходном коде Joda являются частными, поэтому детали YearInfo, включая кеширование, хорошо инкапсулированы. Это хорошая вещь.

Что касается производительности, лучшее, что нужно сделать, - это профилировать свой код и посмотреть, что использует значительное количество ЦП. Для профилирования вы хотите увидеть, имеет ли значение время, проведенное в этом коде, в контексте всего вашего приложения. Запустите приложение под нагрузкой и проверьте, имеет ли значение эта конкретная часть кода. Если вы не видите проблем с производительностью в этом коде даже без кеша YearInfo, то, вероятно, не стоит тратить время на работу с этим кешем. Вот некоторая информация о том, как сделать проверку:
1. Профилировщик производительности для Java-приложения
2. Как найти ресурсоемкий класс в Java?
Тем не менее, обратное утверждение верно - если то, что у вас есть, работает, то оставьте все как есть!

...