25 февраля 2010 г.

Data Oriented Programming вместо ООП

Пара интересных статей:

Musings on Data Oriented Design

Pitfalls of Object Oriented Programming (GCAP)

Суть вопроса, который поднимают авторы, такова -- за последние 30 лет развития IT скорость выполнения команд процессором выросла почти в 50000 раз, но время ответа памяти на запрос (memory latency) уменьшилось всего лишь раз в 10. В итоге мы получаем, что "стоимость" запроса к памяти (в циклах процессора) выросла примерно в 400 раз.

При этом современные компиляторы очень хорошо умеют работать с кодом -- фактически, машинный код, получаемый на выходе из компилятора может вообще не иметь ничего общего, с тем, что изначально было написано человеком -- кроме того, что делает то же самое. Но компиляторы очень мало что делают с данными -- размещение данных в памяти (data layout) генерируемое компилятором фактически очень мало отличается от того, что задекларировал программист в коде (разве что компилятор добавит туда от себя что-то -- vtable например, да выровняет по границам машинных слов). Хотя при современном состоянии дел с memory latency было бы гораздо выгоднее оптимизировать расположение данных под выполняемые задачи.

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

Вместо этого предлагается программисту (пока компиляторы не научились) продумывать размещение данных в памяти исходя из того, как они будут обрабатываться. В частности, в презентации (pdf) Том Албрехт показывает, как им удалось в 3-4 раза ускорить обновление-прорисовку дерева объектов сцены (scene tree) за счет изменения компоновки данных (там, правда, еще про предсказание ветвлений упомянуто)

15 февраля 2010 г.

JCaptcha

Разбирался на прошлой неделе с JCaptcha. Хорошая библиотека, но документация -- отвратная. Огромный разрыв между beginners guide и реальным использованием никак не покрыт. То есть начинаешь читать 5 minutes integration -- все вроде просто. Шаг чуть дальше -- нигде кроме как в исходниках инфы не найдешь.

Последний раз так с MFC мучался в дремучих 90-х. Думал уже, в мире джава таких проектов нет...

Вот, для примера, "переведенный" мною с языка spring-configuration на java код инициализации службы генерации капч:

private static final ImageCaptchaService instance;// = new DefaultManageableImageCaptchaService();

private static final int FONT_SIZE_MIN = 25;
private static final int FONT_SIZE_MAX = 29;

private static final int HEIGHT = 40;
private static final int WIDTH = 200;

static {
//Шрифт, которым будет написана капча. Размер не важен
final Font font = new Font( "Times New Roman", Font.PLAIN, 12 );

//разные буквы разными шрифтами разного размера
final FontGenerator fontGen = new RandomFontGenerator( FONT_SIZE_MIN, FONT_SIZE_MAX, new Font[]{ font } );
//...и разными цветами 
final ColorGenerator colorGen = new RandomListColorGenerator( new Color[]{ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK } );
//однотонный белый фон-подложка. здесь, по-сути, задается размер капчи
final BackgroundGenerator bgGen = new UniColorBackgroundGenerator( WIDTH, HEIGHT, Color.WHITE );
//вырезаем слова от 6 до 9 букв
final TextPaster textPaster = new RandomTextPaster( 6, 9, colorGen );
//список слов можно задать 
final FileDictionary dict = new FileDictionary( "toddlist" );
final WordGenerator wordGen = new DictionaryWordGenerator( dict );
//final WordGenerator wordGen = new ComposeDictionaryWordGenerator( dict );

final ComposedWordToImage wordToImage = new ComposedWordToImage( fontGen, bgGen, textPaster );

final CaptchaFactory factory = new GimpyFactory( wordGen, wordToImage );

final GenericCaptchaEngine engine = new GenericCaptchaEngine( new CaptchaFactory[]{ factory } );

instance = new GenericManageableCaptchaService( engine, 300, 500000, 1 );
}

12 февраля 2010 г.

JavaMail + SSL

Продолжение разбирательств. Краткий итог: итак, самый простой и надежный метод работы с SSL -- использовать
System.setProperty("mail.smtp.ssl.enable","true");

Все остальные настройки как в обычном smtp (только порт обычно 465 вместо 25). Работает с gmail -- проверено

Подробное описание:

Вариант с
System.setProperty("mail.transport.protocol", "smtps")

не работает. Точнее, не совсем работает -- не так, как ожидается. Раскопки в исходниках JavaMail (благо, они доступны) показывают, что свойство mail.transport.protocol используется только методом Session.getTransport() (который без аргументов). Но самой библиотекой этот метод не используется -- предполагается, что его вызывает клиентский код явно. Если вы отправляете почту через явно создаваемый транспорт, и получаете его через session.getTransport() -- свойство mail.transport.protocol будем иметь эффект. Если же вы, как я, отправляете почту через статический метод Transport.send(), то внутри него библиотека ищет подходящий транспорт через вызовом getTransport(Address), что отсылает нас к свойству mail.transport.protocol.rfc822 (rfc822 -- такой "тип адреса" у адреса электронной почты). Если хочется переопределить транспорт для такого типа адресов на smpts -- надо писать
System.setProperty("mail.transport.protocol.rfc822", "smtps");
, либо использовать session.setProtocolForAddress("rfc822", "smpts"). Если просто написать mail.transport.protocol = smtps, то Transport.send() это указание проигнорирует.

В числе прочего это означает, что если вы вместе с mail.transport.protocol = smtps укажете, как описано в документации, свойства типа mail.smpts.host -- они будут проигнорированы (использоваться будут свойства типа mail.smtp.host) и JavaMail будет ломиться на localhost (который используется в качестве адреса smtp сервера по-умолчанию).

JavaMail + SSL

Намучался искать нормальный (авторитетный) источник информации по отправке secure mail с помощью JavaMail. Secure -- это который через SSL и порт 465 (обычно).

В итоге нашел описание на самом java.sun.com (ссылка в заголовке).

Если я их правильно понял, есть 3 основных варианта (для самой свежей версии JavaMail -- 1.4.3)

Первый вариант просто указать системное свойство mail.smtp.ssl.enable=true. Провайдер вроде как должен сам понять, если имеет дело с секьюрным сервером.

Второй вариант -- последней версии можно использовать имя протокола smtps (pops, imaps) -- и, соответственно, все свойства задавать в виде mail.smtps.host, mail.smtps.port, etc.


Последний, самый старый вариант -- инсталлировать SSLSocketFactory через системное свойство mail.smtp.ssl.socketFactory.class

И еще гмайл и похожие сервера требуют установки свойства mail.smtp.starttls.enable=true.

В общем, JavaMail как обычно напоминает шаманские пляски.

5 февраля 2010 г.

String.trim()

Удивительно, но String.trim() не отбрасывает символ неразрываемого пробела 0x00A0. Я был просто поражен -- и нет даже никакой опции, как это убрать.

Более того, \s в регулярках тоже не считает 0x00A0 пробельным символом! Пришлось извращаться в духе [\s\u00A0]

3 февраля 2010 г.

Gallery of Processor Cache Effects

Блог разработчика из Микрософт Игоря Островского. Влияние кэша процессора на производительность