Comments 34
UFO landed and left these words here
Когда читал про рендом, случайно наткнулся этот баг и увидел в переписке хабраюзера, был приятно удивлен. Мир тесен.
UFO landed and left these words here
Как бы я хотел, чтобы для начала этот и подобные посты оптимизировались под RSS.
Простите что беспокою вас, но у вас в первом слове в заглавии одна буква пропущена.
private final Pattern pattern = Pattern.compile(«xxx»);
— А почему его нельзя сделать статичным он вроде потокобезопасный?
Про класс Date не согласен. Строгая типизация для того и есть, что бы везде было написано Date, а не long (а в комментарии приписка //Date), а уже пользуетесь стандартным библиотекой, или нестандартной, или свой пишете — ваше дело.
Ну тут просто смотря как читать ваш текст, если про одну конкретную функцию, то это и не советы оптимизации, а так вы пишите: «нету смысла создавать новый объект даты, если вполне можно обойтись примитивом long», что можно трактовать очень широко. То есть истина где-то посредине, и стоит это наверное выяснить.
В предложенном методе на две строчки локальная переменная типа long лучше типа Date.
Просто то, что вы написали — это очень уж частный случай. В массе своей проще везде использовать Date now — это будет более поддерживаемо и расширяемо. А если поддерживать и расширять не предполагается, то скорее всего, и оптимизация особо не нужна (экономия на спичках уж точно).
public boolean isValid(Date start, Date end) {
long now = System.currentTimeMillis();
return start.getTime() < now && now < end.getTIme();
}


Оптимизация одного частного случая. Написать тест на разное текущее время или сделать проверку, были ли данные валидны на некий момент, вы уже не сможете. Экономия на спичках здесь может создать нехилую такую проблему. Плюс, чисто семантически странно проверять даты на основе timestamp'а. В любом случае, в итоге всегда получается, что кроме timestamp'а нужно узнать часовой пояс, каким-либо образом отформатировать дату и т.п. И в этом случае лучше везде таскать за собой зависимость на Date now, чем усложнять код хардкодами текущего времени.

Это всё моё имхо, конечно.
Абсолютно с Вами согласен. У нас система разделена на модули. Есть ХХХ модуль (веб сервис), который является высоконагруженным. Требования к одному серверу 500 рек/сек и время ответа меньше 50мс для 99% реквестов. Когда стоят такие требования — вопрос подготовки данных для ускорения работы сервера — это вовсе не проблема.
key.setDeliveredDateContent(truncateToHours(byPeriodKey.getContentTimestamp()));
key.setDeliveredDateAd(truncateToHours(byPeriodKey.getAdTimestamp()));

Знакомые строки :)
Кстати Escape Analysis сам увидит что объект Date метода не покидает:
    public boolean isValid(Date start, Date end) {
        Date now = new Date();
        return start.before(now) && end.after(now); 
    }

И сам соптимизирует к System.currentTimeMillis();

А код останется чуточку более читаемым.

Хотя я сам, конечно, new Date() уже почти никогда не пишу.
Насколько я знаю (поправьте если не так), чтобы JIT начал анализировать код на убегание объектов и прочие продвинутые вещи, он должен быть действительно «горячим». Не уверен, что в условиях обычного веб-сервера это часто достигается. Так можно в куче мест понадеяться на JIT, он их все по-отдельности не посчитает достаточно горячими, и в итоге замедление набежит существенное.
Чтобы JIT начал такой анализ, самое главное чтобы был выставлен флаг -XX+DoEscapeAnalysis. А насколько «горячим» должен быть код для работы JIT контролируется флагом -XX:CompileThreshold (по умолчанию 10 000 вызовов метода, если мне память не изменяет, по крайней мере с «серверным» компилятором).

Всё это относится только к HotSpot JVM, конечно. У других JVM другие настройки.
1. Запускается приложение с включенным profile-агентом
2. Подключается профилировщик
3. ??????
4. PROFIT
ну я бы не был так уверен =)

если кратко:
1) имеется процесс tasktracker
2) он периодически ломится на удаленную машинку за заданиями
3) на приходящий таск подымает отдельную jvm и выполняет там задание(таск)
4) грохает jvm от таска

так как каждый jobs состоит из большого количества tasks, то оптимально reuse уже поднятую jvm для всех заданий в пределах одного job, так как проблем с класпасом у нас точно не будет, но даже в этом случае сами разработчики предупреждают о потенциальных утечках ресурсов (если ваш код течет, то одно дело утечка в пределах одного таска, и совсем другое когда у вас пару сотен или тысяч тасков отработаться в пределах одной jvm).

Поэтому вопрос про то, как профайлили hadoop мне тоже был бы интересен.
Никак. Я профайлил отдельно мап и редюс методы в юнит тестах с продакшн логами. По ним смог определить узкие места нашего кода. Что касается более сложных задач — например, распределения ключей по редюсам, то для этого использовалась мониторилка самого хадупа. По ней четко можно понять где именно проблема и туда уже копать в каждом конкретном случае.
1. Проблема Date не в deprecated-методах, а в том, что он mutable и дает соблазн изменить объект, передаваемый в аргументе. Здесь, как правильно заметил автор, пригодится joda. Если посмотреть исходники конструктора Date(), то там всего лишь вызов currentTimeMillis(). Если хотите оптимизировать такой код и вызовов действительно много — вынесите за скобки вызов currentTimeMillis (он по какой-то неведомой причине не такой уж и быстрый), сравнивайте long'и.
2. Про Not Null — сам по себе метод весьма странный, так вообще не стоит писать. А еще есть паттерны immutable и null object (не путать с null).
3. В блоке про Regexp, по всей видимости, после правки стоит убрать упоминание ThreadLocal'а.
4. Пример про truncateToHours по неясной причине просто дату заменяют на дату UTC. А вообще это делается проще: new Date(date.getMillis() / 3600000 * 3600000) (если есть уверенность, что мы работаем в часовом поясе, кратном одному часу, что характерно для большинства задач).
5. Про хеш-коды тоже не согласен. Опять же есть паттерн immutable, особенно важный для объектов, которые кладутся в Set (Map), там в качестве оптимизации можно сделать кеширование hashCode, как это сделано, например, в классе String. А использование HashCodeBuilder — личный выбор разработчика, лишь бы equals->hashCode контракт был сохранен.

P.S. Мне не хватает кармы, но, простите, я бы за статью влепил бы минус.
я влепил за вас :) И вот почему. Я не понимаю, какие задачи решает статья и к чему призывает читателей. «Не создавайте лишних объектов»? Это можно было одной строчкой написать.

Только вот создание объекта — это очень (ОЧЕНЬ!) быстрая операция. Поэтому хоть сколько заметного прироста перфоманса от замены в произвольном месте объекта на что-то — не будет с вероятностью 99,9%.

Если ускорение работы приложения от убирания операции создания объекта и возникает, то, в основном, по двум причинам: локальность данных (совершенно отдельная тема, на которую в статье никаких намёков не было) и снижение нагрузки на GC (плодим меньше мусора). Так вот, если вы уверены, что приложение тормозит из-за GC, то есть если есть реальная нагрузка на GC, то надо включать профилятор и совершенно по месту смотреть, где у вас плодятся объекты. И именно в этом месте решать проблему. А Date это будет, Format, String или что-то ещё — вообще пофиг.
надо включать профилятор и совершенно по месту смотреть
Не, ну человек пишет же, что "периодически приходится пользоваться профайлером", наверняка не просто так. А раз уж и написать об этом решил, то видимо и профит заметный был.

Хотя, лично у меня, если честно, первой реакцией на статью было съязвить что-нибудь. Но, подумал и передумал. Хотя интересного в статье мало, а большая часть материала — просто здравый смысл и будни программиста, но все же это напоминание о том, что не следует забывать про оптимизацию, и самый простой и будничный кусок кода может с аппетитом откушать процессора. Лишь бы оптимизация не была преждевременной. А то я вот, например, не так давно увидел в старом, но добротном коде веб-сервиса блок synchronized и решил заменить его на что-нибудь более продвинутое из того, что появилось в Java 5/6. НО! Перед тем как сделать это, сделал замеры производительности. Оказалось, что работа в этом блоке длится 0.001% (одна тысячная процента) от общего времени вызова метода веб-сервиса. «Не все то золото, что блестит» — подумал я, и оставил все как есть.
Про SimpleDateFormat и согласен, и несогласен одновременно.
Действительно, это тяжелый метод, который на практике в нашем случае сжирал существенную долю CPU высоконагруженного веб-сервера.
Но я не соглашусь с тем, что виной тому создание нового SimpleDateFormat каждый раз. Медленным здесь является сам процесс конвертации в строку заданного формата. Я эту проблему решил, написав свой конвертер HttpDate, заточенный под конкретный формат, фигурирующий в HTTP протоколе.
Кстати по поводу hash и equals — eclipse умеет генерировать очень симпотичные перекрытия
Not null:
Здесь тоже можно использовать static :)
Постоянные проверки на null сильно засоряют код.

private static final Item ItemObj=new Item(); // =Item.getEmptyStaticObject();

public Item someMethod() {
    //some logic
    if (something) {
        Item item = new Item();
        fillItem(item);
        return item;
    }else{
       return ItemObj;
    }
}
Only those users with full accounts are able to leave comments. Log in, please.