Monday, January 24, 2011

Причинный тест Грейнджера на Java

В своей прошлой заметке о причинном тесте Грейнджера я рассказал о его применении к данным о производстве яиц и количестве куриц-несушек в США. Я не рассказал, однако, как же этот тест провести самостоятельно и что значат все эти числа в таблицах. Рассказываю.

Вероятностный тест Грейнджера поддерживается многими статистическими пакетами, такими как Stata или R, но гораздо интересней написать реализацию самому. Заодно это поможет разобраться в тонкостях и деталях. Будем реализовывать его на Java. Для этого нам понадобиться Apache Commons Math в ней мы найдем реализации F-статистики и линейной регрессии.

Thursday, January 20, 2011

Курицы, яйца, причинный тест Грейнджера или кто был первым?

Что было раньше, яйцо или курица?

Несмотря на продолжающиеся и по сей день дебаты, ответ на этот вопрос был дан математиками Вальтером Турманом и Марком Фишером в 1988 году. В своей работе "Chickens, Eggs, and Causality, or Which Came First?" используя аппарат математической статистики, они доказали, что яйца были раньше. Однако с тех пор прошло больше 20 лет, курицы и яйца могли измениться...

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

Friday, January 14, 2011

Потокобезопасный DateFormat


"Является ли класс java.text.DateFormat потокобезопасным?". Этот вопрос очень любят задавать на собеседовании по вакансии Java-программиста. Ответ на него – нет, не является. Вот только собеседующие редко спрашивают, а как же тогда быть, если все-таки надо его использовать в многопоточном окружении? Меж тем в реальных задачах мало просто знать, что DateFormat не потокобезопасен, было бы неплохо еще и знать способ решения проблемы. Сравнению возможных вариантов решения и посвящен данный пост.

Элементарная логика и гугл родили на свет пять вариантов:
  1. Вариант решения "в лоб". Если DateFormat не потокобезопасный, давайте синхронизируем доступ. А чтобы не писать каждый раз блокировки вручную, воспользуемся паттерном декоратор. В точности, как это реализовано в Collections.synchronizedList() итп.
  2. Другой, не менее очевидный вариант, давайте создавать новый экземпляр класса на каждый вызов.
  3. Воспользуемся ThreadLocal для хранения одного экземпляра DateFormat на поток.
  4. Воспользуемся классом из Apache Commons Lang FastDateFormat. Пожалуй основной недостаток этого варианта – он не поддерживает парсинг даты. Поддерживается только печать.
  5. И последний, но отнюдь не маловажный вариант – использовать библиотечку joda-time. К сожалению, эта библиотека поддерживает не все паттерны стандартного DateFormat поэтому, не во всех случаях будет возможно на нее переключиться.

Что ж, пусть тест производительности решит вопрос и расставит наконец точки над i. В данном тесте проверялась скорость выполнения 100000 операций парсинга и форматирования в каждом из 20 потоков работающих одновременно.Тест запускался дважды, первый раз с ключиком JVM -server, второй раз с ключем -client.

Полный исходный код теста можно скачать здесь. Для запуска, так же, понадобятся последние версии библиотек Apache Commons Lang и Joda Time.

Результаты получились следующие:
Время парсинга (мс)Время форматирования (мс)
Synchronized java.text.DateFormat12110 / 137513484 / 2766
New instance per call java.text.DateFormat4954 / 102343750 / 7546
ThreadLocal java.text.DateFormat1703 / 2687766 / 656
Apache FastDateFormatНе поддерживается1500 / 2297
Joda Time1062 / 1828500 / 1047
SimpleDateFormat*1697 / 2656758 / 652
* - это референсное время, в данном случае мы эффективно используем DateFormat в однопоточном режиме. Создав для каждого из 20 потоков собственный экземпляр класса SimpleDateFormat.

Первое время - это время выполнения для серверной JVM, второе время - для клиентской JVM.


В случае серверной версии, с впечатляющим отрывом лидирует Joda  Time,  обгоняя даже референсную версию от SimpleDateFormat.

В случае форматирования при клиентской версии JVM в отрыв уходит версия с ThreadLocal.

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