![]() |
"Абсолютно случайным образом ударяя по
клавишам пишущей машинки, гипотетическая
обезьяна рано или поздно напечатает одну
из пьес Шекспира."
|
Thursday, 14 May 2015
Линейность математического ожидания или Typewriter Monkey
Tags:
algorithms,
dynamic programming,
expected value,
Google Code Jam,
linearity,
Typewriter Monkey
Вы знаете что такое математическое ожидание? Тогда сегодня я вам предлагаю поразмыслить над следующей задачкой по программированию Typewriter Monkey.
На прошлых выходных я участвовал в конкурсе Google Code Jam и единственная задача, которая не далась мне полностью оказалась задача про обезьян с печатными машинками.
Итак, для начала, вкратце об условиях конкурса. Условия задачи описаны в тексте по ссылке выше. Решать задачу можно на абсолютно любом языке программирования. На странице с заданием можно скачать два тестовых набора данных: маленький и большой. Данные в обоих случаях структурированы одинаково, отличие в ограничениях на начальные условия и количество времени, которое можно потратить на генерирование ответа.
В нашем случае ограничения следующие:
Friday, 8 February 2013
Regular Expressions basics course
И снова регулярные выражения. Как я говорил, многие почему-то боятся использовать регулярные выражения в повседневной жизни технического специалиста. Есть даже известная фраза:
"Иногда люди сталкиваются с проблемой и думают: "Для решения я использую Регулярные Выражения". Теперь у них две проблемы." (c) история появления фразы
Ключ к решению задач и преодолению страха перед формальными языками (коим является RegExp) – обучение, не так ли? И сегодня я хотел бы поделиться с Вами своим курсом по основам регулярных выражений. 20 кратких слайдов, которые могут изменить (я надеюсь) Ваш подход к поиску информации. Вы не представляете сколько Вы теряете не пользуясь регулярками. Их поддержка встроена во все современные языки программирования, во многие утилиты и консольные приложения. И по сути, если где либо Вы встречаете слово шаблон или маска, то в половине случаев это будет регулярное выражение.
Интересно? Ай-да под кат.
index
"Иногда люди сталкиваются с проблемой и думают: "Для решения я использую Регулярные Выражения". Теперь у них две проблемы." (c) история появления фразы
Ключ к решению задач и преодолению страха перед формальными языками (коим является RegExp) – обучение, не так ли? И сегодня я хотел бы поделиться с Вами своим курсом по основам регулярных выражений. 20 кратких слайдов, которые могут изменить (я надеюсь) Ваш подход к поиску информации. Вы не представляете сколько Вы теряете не пользуясь регулярками. Их поддержка встроена во все современные языки программирования, во многие утилиты и консольные приложения. И по сути, если где либо Вы встречаете слово шаблон или маска, то в половине случаев это будет регулярное выражение.
Интересно? Ай-да под кат.
Regular Expression quiz
Понравился Regular Expression Crossword из предыдущей записи? У меня для Вас хорошая новость – некоторое время назад я составил небольшой опрос-викторину, когда готовил курс по изучению регулярных выражений.
Регулярные выражения вообще говоря очень интересная тема. Дело в том, что они нас окружают практически везде, поддержка есть во всех языках программирования, но многие разработчики почему-то страшно оттягивают момент познания. Прямо какая-то фобия регулярок.
Итак, считаете себя несокрушимым ниндзя-экспертом Регулярок? Не уверены, но хотели бы попробовать свои силы? Новичёк, но не знаете с чего начать обучение? Для Вас ниже всего дестяь (10) усложняющихся вопросов на знание различных тем регулярных выражений.
index
Регулярные выражения вообще говоря очень интересная тема. Дело в том, что они нас окружают практически везде, поддержка есть во всех языках программирования, но многие разработчики почему-то страшно оттягивают момент познания. Прямо какая-то фобия регулярок.
Итак, считаете себя несокрушимым ниндзя-экспертом Регулярок? Не уверены, но хотели бы попробовать свои силы? Новичёк, но не знаете с чего начать обучение? Для Вас ниже всего дестяь (10) усложняющихся вопросов на знание различных тем регулярных выражений.
Thursday, 7 February 2013
Regular Crossword
Tags:
algorithms,
crossword,
quiz,
regex,
regular expression
![]() |
| Regular expressions crossword |
Любите головоломки? Знаете регулярные выражения? Тогда время Че настало... Я не пожалел потраченного времени на решение.
Итак, у нас есть соты. В каждой ячейке должна стоять буква латинского алфавита. Каждое регулярное выражение должно полностью "матчить" свою строку. Таким образом каждая буква будет провалидирована тремя разными регулярками.
Для получения читабельного PDF – кликните на картинку.
Monday, 9 January 2012
Handmade lamp/alarm clock with Android charge
Tags:
Android,
DIY,
lamp alarm
Взбрело мне в голову поиграться с микросхемами. Поскольку от схемотехники я уже далёк, то решил сделать для начала что-то простое, но полезное, а затем уже двигаться к сложному и just-for-fun. Выписал список идей, составил таблицу истинности плюсов и минусов, отсортировал в порядке усложнения...
В итоге, решил сделать световой будильник с использованием Андроида. В чём суть?
Saturday, 24 September 2011
Influence, Robert Cialdini
Tags:
books,
Cialdini,
influence,
psychology
В последнее время я стал достаточно много читать и решил поделиться немного с вами. Очередную книгу по психологии мне посоветовал друг. Встречайте: Robert Cialdini, Influence.
Честно говоря, я люблю психологию в доступном изложении, но, к сожалению, к подобным книгам отношусь с опаской. Слишком громкое название, за которым автор обычно прячет достаточно известные принципы, которые разжевываются по триста раз и вода в тексте, в которой утопаешь, забыв о сути книги. Не совсем понимаю почему многократное повторение так любят авторы подобной литературы, но мне это не подходит. Именно по данной причине, например, я не могу читать Карнеги Дейла. Так что же мне понравилось в данной книге?
Sunday, 19 June 2011
Immigration process (search for a work)
Tags:
expat,
immigration,
work permit,
work search
"Люди думают, что будут счастливы, если переедут в Париж, а потом оказывается: куда бы ты ни поехал, ты берёшь с собой себя." (с)овершенно точно.
Сегодня мы поговорим о вопросах поиска работы за пределами родной страны. Данный пост по сути родился из моего опыта и всё учащающихся вопросах о процессе иммиграции. Хочется начать рассказ с самого начала: с поиска работы, ибо только подписанный контракт на сегодняшний день - залог долгосрочной визы. Речь, естественно об IT.
Данный пост почему-то захотелось оформить в стиле поучительного TO-DO списка. Итак, поехали:
0. Определись с тем, чего именно ты хочешь. Какова твоя цель, что ты за человек, где истоки твоего желание, чтобы не получилось как в эпиграфе.
1. Страна или страны. Этот выбор стоит сделать на достаточно раннем этапе.
1.1. Изучи иммиграционное законодательство целевой страны. Обычно достаточно изучить материалы на сайтах посольств или консульств. Там есть большинство документов и описанных процессов.
1.2. Узнай какие типы виз тебе подходят. В некоторых странах действуют программы для "Highly Skilled Immigrants", по которым тебе вообще не нужен рабочий контракт, для получения визы. Достаточно соответствовать некому набору критериев. (Большинство таких программ, к сожалению, закрылись или в процессе закрытия)
1.3. Изучи рынок. Узнай какие вакансии преимущественно попадают на IT рынок данной страны, какие у них зарплаты. Здесь сильно помогают monster.com и glassdoor.com
1.4. Изнай сколько налогов ты будешь платить, сколько стоит жилье, сколько тебе понадобится на еду (для начала умножай на два с тем расчетом, что ты будешь тратить больше пока не освоишься).
2. Вылижи резюме.
2.1. Резюме должно быть на английском, а не на его подобии.
2.2. Вот собственно: CV style. Мои взгляды особо не поменялись :)
2.3. Составь сопроводительное письмо. Небольшое, не раздражай читающего, но из которого станет понятно, что ты адекватный человек, ищешь работу и тебе нужна виза. Последний пункт очень важен: лучше не тратить времени зря и искать сразу тех, кто понимает, что на данный момент ты ВНЕ целевой страны.
2.4. Ну и наконец, используй PDF :) Хотя лучше иметь заготовки в разных форматах.
3. Параллельно можно начинать искать вакансии, но инфо из первого пункта стоит знать заранее, чтобы чувствовать себя более комфортно в разговоре.
3.1. Составь список компаний, которые работают в данной стране. Выписывай и крупные, и маленькие. Можно искать через тот же Monster например, но одного источника мало. Многие крупные компании вообще не работают через агенства - о их вакансиях можно узнать только у них на сайте.
3.2. Составь себе табличку, где будешь собирать данные о компаниях, их контакты и ссылки на вакансии, на которые ты выслал своё резюме. Стоит помнить куда именно ты отсылал письма и как называются вакансии (может сильно пригодится).
3.3. Будь готов, что если кто-то заинтересуется - будут звонить. Телефонный контакт для HR очень важен: он более надёжен + позволяет хоть немного оценить адекватность и наличие языка. Если можешь говорить только в определённое время - укажи это в резюме.
3.4. Писать надо всем. Неважно есть у компании открытая вакансия или нет. Не важно, что в вакансии указано, что требуются жители только определённой страны. Всякое бывает. Главное, ты не должен скрывать, что ты сам находишься вне этой определённой страны.
3.5. Если какая-то компания нравится больше всего, через день после отсылки резюме перезвони и уточни получили ли они твоё письмо.
4. Ну и BodyShop
4.1. Такие фирмы, как Епам, Люксофт и множество других перевозят людей. Они получают процент от твоей з/п в итоге. Этот вариант стоит рассматривать в самый последний момент, ибо условия работы зачастую пониже будут + есть свои нюансы. Из позитивных моментов - компания берёт на себя всё оформление.
5. Немного психологии.
5.1. Будь готов, что многие не отвечают вообще.
5.2. Пойми, что процесс может быть очень длительным.
5.3. Если кто-то пригласил на собеседование, это еще не победа. Иногда надо пройти 6-8 собеседований в одной и той же компании, чтобы устроится на работу.
P.S. Если кто-то не в курсе про источник картинки: Поросёнок Петя
Wednesday, 6 April 2011
PostgreSQL. Redirect data to child partition.
Tags:
db,
partitioning,
plpython,
postgres,
variable table name
На одном из недавно "вверенных" проектов жил поживал PostgreSQL с настроенным разбиением данных по таблицам-разделам в зависимости от значений (т.н. Partitioning). Особенности работы с БД были таковы, что раз в сутки в таблицы "вливалось" достаточно большое кол-во данных (десятки миллионов строк) и до следующего "вливания" база работала только на отдачу данных.
Проблема, а точнее даже не проблема, а пожелание заключалось в следующем: ПО, которое занималось подготовкой, фильтрацией и, собственно заливкой данных, занималось еще и тем, что вычисляло тот самый, нужный раздел (child table), в который данные нужно сложить. Это приводило к:
- невозможности менять условия разбиения данных достаточно гибко (изменения должны быть синхронизированы на стороне БД и кода);
- иногда в разделы попадали некорректные данные, так как заливка данных осуществлялась пакетно, с помощью операции COPY и нужный раздел определялся для всего пакета один;
- необходимо было заранее создавать таблицы разделов.
Решение, приведенное ниже - не панацея, но кому-то может пригодиться:
CREATE TRIGGER redirect_to_child
BEFORE INSERT ON parent
FOR EACH ROW
EXECUTE PROCEDURE redirect_to_child();
Затем, экспериментируя с процедурой redirect_to_child() выяснилось, что на стандартном PlPgsql написать достаточно гибкую функцию, которая бы перенаправляла данные в нужный раздел не получается, так как на этапе запуска функции не известно название таблицы, в которую нужно вставлять данные. Таким образом приходиться использовать EXECUTE для формирования динамического SQL, но это не решает всех проблем, так как теперь нельзя использовать NEW.*, потому что полученный SQL выполняется вне контекста триггерной функции и соответственно не видит структуры NEW.
В PostgreSQL 8.4 появилось ключевое слово USING, которое позволяет обойти проблему с использованием NEW.*, но скорость работы данного триггера оставляла желать лучшего.
В результате всех экспериментов родился небольшой велосипедик на PlPython, который сам создаёт нужные таблички и перенаправляет вставку данных. Нижеприведенный кусочек кода, решает все задачи, описанные в начале статьи, а по времени работает всего около 5-ти раз медленнее "чистой" вставки, что для моих условий было более чем приемлемо. Собственно код:
CREATE OR REPLACE FUNCTION redirect_to_child()
RETURNS trigger AS
$BODY$
import datetime
# TD['new'] -> inserted data
new_data = TD['new']
values = new_data.values()
date_occured = new_data['occured'].split()[0]
s_year, s_month = date_occured.split('-')[:2]
# TD['table_name'] -> table name, that triggered this function.
parent_table_name = TD['table_name']
# Child table name pattern is <parent_table>_<year>_<month>.
child_table_name = '_'.join([parent_table_name, s_year, s_month])
try:
insert_plan = SD[child_table_name]
except KeyError:
# Check whether child table exists.
child_table_result = plpy.execute(("SELECT * FROM information_schema.tables"
" WHERE table_catalog = CURRENT_CATALOG"
" AND table_schema = CURRENT_SCHEMA"
" AND table_name = '%s'") % (child_table_name, ))
if child_table_result.nrows() == 0 :
# Need to create child table
year = int(s_year)
month = int(s_month)
min_range_date = datetime.date(year, month, 1)
max_range_date = datetime.date(year + ((month + 1) / 12), (month + 1) % 12, 1)
create_sql = ("CREATE TABLE %(child)s ("
" id BIGINT DEFAULT nextval('%(parent)s_id_seq'::text) PRIMARY KEY,"
" CHECK ( occured >= DATE '%(min)s' AND occured < DATE '%(max)s' )"
") INHERITS (%(parent)s);") \
% {'parent': parent_table_name,
'child':child_table_name,
'min':min_range_date.isoformat(),
'max':max_range_date.isoformat() }
plpy.execute( create_sql )
plpy.execute( "ALTER TABLE %s OWNER TO tableowner;" % child_table_name )
# Prepare insertion plan.
questions_marks = ','.join(['$%d' % x for x in xrange(1, len(new_data) + 1)])
col_types = plpy.execute( ("SELECT column_name, data_type"
" FROM information_schema.columns"
" WHERE table_catalog = CURRENT_CATALOG"
" AND table_schema = CURRENT_SCHEMA"
" AND table_name = '%s'"
" AND column_name <> 'id';")
% parent_table_name );
type_hash = dict((column["column_name"], column["data_type"])
for column in col_types)
column_names = new_data.keys();
types = [type_hash[k] for k in column_names]
insert_sql = ("INSERT INTO %s (%s) VALUES (%s);" %
(child_table_name,
', '.join(column_names),
questions_marks))
insert_plan = plpy.prepare(insert_sql, types)
# Cache insertion plan for reuse in the same transaction.
SD[child_table_name] = insert_plan
# Insert data to child table
plpy.execute( insert_plan, values )
# Skip insertion to parent table
return "SKIP";
$BODY$
LANGUAGE 'plpythonu';
ALTER FUNCTION redirect_to_child() OWNER TO tableowner;Blogspot expandable posts
Tags:
cut,
expandable,
lj-cut,
Read more,
usability
Давно я не писал сюда. Сегодня решил исправится и первым делом настроил себе красивый скрипт для длинных статей.Встречайте:Ссылка "Read more" появляется только в тех статьях, которые действительно этого заслуживают (и где я собственноручно проставил нужный тег). Работает всё предельно просто, код взят отсюда. Правда пришлось самую малость допилить.
Tuesday, 22 June 2010
Видео прокси для вещания в локальной сети
Tags:
broadcasting,
video proxy,
vlc
В период чемпионата мира по футболу очень хотелось следить за ходом матчей в живую, да вот беда - работа. Решение казалось бы банально - on-line видео трансляции, но не я один такой заинтересованный оказался. А при 30-40 одновременных потоках входящий Интернет канал оставляет остальным сотрудникам офиса лишь маленькую надежду на закачку чего бы то ни было.Очень быстро родилась идея организовать видео прокси, которое бы принимало on-line трансляцию и раздавало видео поток в сети. Локальный трафик не так значим, как входящий интернет трафик, потому приступил к реализации. Выбор пал на VLC media player, который сначала показался несколько монстроидальным, но в дальнейшем оправдал все надежды.
Итак, что такое VLC player? Это open-source программный комплекс, позволяющий творить с видео чудеса. В плейере уже находиться масса возможностей, фактически плейер может одновременно выступать и сервером и клиентом. В поставку входят интерфейсы для удалённого управления (telnet, http), так что можем смело ставить vlc на консольную виртуальную машину (здесь и далее все команды приводятся для Ubuntu):
sudo aptitude install vlc vlc-plugin-*
Далее запускаем VLC с активным http интерфейсом удалённого управления:
vlc -vvv -I http --http-host 10.1.6.3:8181
, здесь
- -vvv - verbose опция (количество букв v отображает уровень логов)
- -I - включает один из интерфейсов удалённого управления (здесь http)
- --http-host - задаёт имя (ip) которое пользователь должен ввести, чтобы попасть в админ часть и порт, который будет слушать встроенный сервер
В принципе данного интерфейса хватает для экспериментов. Для лучшей наглядности лучше сразу же нажать кнопочку "Help".Первым делом, я нажал кнопку "Open", ввёл адрес сервера (для экспериментов было выбрано футбольное on-line вещание ICTV) и... И насладился цветной картинкой ASCII видео в консоли удалённого сервера. Поборов восхищение и отключив видео - нашел в http интерфейсе кнопку "Stream output", которая и привела меня к победе. Догадался одновременно заполнить обе секции перед нажатием кнопки "Play":
- в Input (Open кнопка) адрес вещания в интернете.
- в Stream output выбрал http, ввёл адрес (всё тот же 10.1.6.3), указал порт (на этот раз 8080, чтобы не пересекаться с админкой) и отметил тип кодирования "MPEG TS"
И на последок консольный вариант запуска:
vlc -vvv -I http --http-host 10.1.6.3:8181 http://<internet.on-line.video.url> -sout "#transcode{vcodec=mp2v,vb=1024,scale=1}:std{access=http,mux=ts,dst=10.1.6.3:8080}"
Friday, 18 June 2010
Несколько наблюдений о PostgreSQL
Tags:
create index,
db,
postgres
1. Postgresql 8.4 + PostGis 1.5.1 оказался в 4 раза производительнее при использовании st_intersects на большом кол-ве данных, нежели Postgresql 8.3 + PostGis 1.32. Слышали про магическое "\d" в psql? Не знаете какие же запросы делает этот оператор? Вот вам лекарство: "\set ECHO_HIDDEN t"
3. Как вывод из предыдущего пункта, напрашивается решение следующих вопросов:
* "А как создать таблицу, но только если она еще не существует?"
* "А как создать индекс, но только если он еще не существует?"
В Postgresql это решается обёрткой создания в функцию следующего вида:
CREATE OR REPLACE FUNCTION create_tables_if_not_exist()
RETURNS void AS
$BODY$
BEGIN
IF NOT EXISTS ( select * from pg_class where relname = 'countries' ) THEN
CREATE TABLE countries
(
id serial NOT NULL,
geom geometry,
name character varying(80),
cid integer,
CONSTRAINT countries_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
END IF;
END;
$BODY$ language 'plpgsql';
Monday, 29 March 2010
Neo4J - java graph DB
Tags:
graph database,
graphs,
neo4j,
nosql
Недавно я рассказывал про граф ориентированные базы данных. А сегодня хочу поделиться с Вами историей использования одной из них. Встречайте Neo4J.Итак немного о самой системе: Neo4J предлагает Вам полноценную базу данных с транзакциями, индексами (Lucene), несколькими режимами работы и низким порогом вхождения, благодаря очень простой структуре. Все коды открыты и доступны, а приложение поставляется под двойной лицензией AGPL для некоммерческого использования и тарифная сетка для коммерческого. Для начала использования данной базы Вам достаточно знать джаву и понимать чего Вы хотите от сетевой структуры данных (графа).
Мне, при моём знакомстве, была интересна производительность при больших объемах данных и удобство работы с самой БД. Начнём с удобства и создадим базу данных с большим кол-вом вершин и ребёр. Для этого используем специальный класс доступа к БД, который оптимизирован под вставку:
batchGraphDb = new BatchInserterImpl( dbpath, stringProps );
batchIndexService = new LuceneIndexBatchInserterImpl( batchGraphDb );
, где dbPath - путь к файлам будущей базы данных, а stringProps - настройки.
Cоздадим несколько вершин следующим образом:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("a_key", 5);
properties.put("b_key", "some string");
long createdNode = batchGraphDb.createNode(properties);
batchIndexService.index(createdNode, "a_key", properties.get("a_key"));
Далее в идеале стоит вызвать метод batchIndexService.optimize(); который приведёт индексы в порядок и продолжим создавать рёбра:
Map<String, Object> edgeProperties = new HashMap<String, Object>();
edgeProperties.put("length", 345);
edgeProperties.put("version", "7.5");
long startNodeId = batchIndexService.getSingleNode("a_key", 5);
long endNodeId = batchIndexService.getSingleNode("a_key", 7);
batchGraphDb.createRelationship(
startNodeId,
endNodeId,
DynamicRelationshipType.withName("trust"),
edgeProperties);
Не хитрые манипуляции создают ребро из одной вершины в другую с типом "trust" и собственными свойствами. Ну и на последок закрытие соединения с БД:
if ( null != batchIndexService ) batchIndexService.shutdown();
if ( null != batchGraphDb ) batchGraphDb.shutdown();
Данные готовы, а нам не терпиться проверить её производительность. Показатели качества будут озвучены в следующем посте, а пока можно ознакомиться с другой статьей на эту тему: MySQL vs. Neo4j on a Large-Scale Graph Traversal
Wednesday, 17 March 2010
Graph DB
Tags:
graph database,
graphs
Что такое граф, я думаю все знают, а вот зачем для них понадобились свои собственные базы данных? Дело всё в том, что для структуры данных типа граф, набор действий зачастую несколько отличается от привычных нам вставок, обновлений и выборок по заданным условиям. Чего только стоят поиск в ширину и глубину. В принципе на небольших объемах данных традиционные способы представления себя оправдывают, но если предположить, что ваш граф начинает расти и в нём становится несколько миллионов вершин и десятки миллионов связей - реляционные базы данных загибаются под попытками провернуть нужное кол-во join-ов дабы удовлетворить многим условиям выборки при прохождении графа в случае поиска.
Что представляет собой граф ориентированная БД - это хранилище, которое использует некоторые априорные знания о графах, для формирования своей внутренней структуры. В таких базах поиск по критерию зачастую происходит не самым эффективных способом, а вот вычитка связей вершины, и вершин связей сильно оптимизирована. Таким образом обход графа (traversing) становиться операцией, которая в несколько раз быстрее аналогичной родственной реализации в реляционных БД.
Для ознакомления можно взглянуть на:
Friday, 15 January 2010
10 истин про Erlang...
Tags:
erlang,
functional language
Недавно заинтересовался функциональными языками и так уж случилось, что под руки попался Erlang. А что Вы о нём знаете?1. Erlang - еденица интенсивности телефоммуникационной нагрузки (кол-во траффика)
2. Erlang - датский учёный конца 19, начала 20 веков. Вплотную занимался теориями массового обслуживания и распределениями веротностей разнообразных параметров в разных сферах коммутационных сетей. Его формулы и теории используют по сей день. Его самый известный труд описывает принцип работы Коммутатора с точки зрения мат. статистики и по сути вводит понятие семафора.
3. Erlang - функциональный язык программирования, разработанный компанией Ericsson, оптимизированный для многопоточности и до сих пор использующийся в больших системах реального времени.
4. В Erlang языке нет переменных. Точнее они представленны в виде неизменяемых констант. Никакие две переменные не могут иметь одно и то же имя в пределах их области видимости.
5. Erlang исполняется в виртуальной машине.
6. Парадигма программирования на Erlang позволяет порождать процессы. Erlang-процессы это что-то сродни привычным всем потокам, но со своим уникальным адресным пространством и гораздо более легковеснее ОС-зависимых потоков. Erlang виртуальная машина сама управляет своими процессами.
7. Любые два Erlang-процесса могут обмениваться сообщениями, даже если они запущены в виртуальных машинах на разных компьютерах. Для этого достаточно знать IP-адрес и пароль доступа к запрашиваемой виртуальной машине.
8. Erlang позволяет менять код на лету.
9. Erlang не поддерживает строки напрямую, зато поддерживает массивы. Модель представления массива в памяти - однонаправленный список. Посему в языке определены стандартные операции "добавить в голову массива элемент" и "взять\удалить головной элемент массива"
10. Erlang поддерживает циклы только за счет хвостовой рекурсии. Правда компилятор-интерпретатор умён и если придерживаться определённых правил рекурсия при исполнении всё же будет представлена циклом, но это не меняет впечатления программиста при прочтении исходных кодов.
index
3. Erlang - функциональный язык программирования, разработанный компанией Ericsson, оптимизированный для многопоточности и до сих пор использующийся в больших системах реального времени.
4. В Erlang языке нет переменных. Точнее они представленны в виде неизменяемых констант. Никакие две переменные не могут иметь одно и то же имя в пределах их области видимости.
5. Erlang исполняется в виртуальной машине.
6. Парадигма программирования на Erlang позволяет порождать процессы. Erlang-процессы это что-то сродни привычным всем потокам, но со своим уникальным адресным пространством и гораздо более легковеснее ОС-зависимых потоков. Erlang виртуальная машина сама управляет своими процессами.
7. Любые два Erlang-процесса могут обмениваться сообщениями, даже если они запущены в виртуальных машинах на разных компьютерах. Для этого достаточно знать IP-адрес и пароль доступа к запрашиваемой виртуальной машине.
8. Erlang позволяет менять код на лету.
9. Erlang не поддерживает строки напрямую, зато поддерживает массивы. Модель представления массива в памяти - однонаправленный список. Посему в языке определены стандартные операции "добавить в голову массива элемент" и "взять\удалить головной элемент массива"
10. Erlang поддерживает циклы только за счет хвостовой рекурсии. Правда компилятор-интерпретатор умён и если придерживаться определённых правил рекурсия при исполнении всё же будет представлена циклом, но это не меняет впечатления программиста при прочтении исходных кодов.
Sunday, 8 November 2009
boolean - боремся за Java память...
У Вас когда-либо случались такие ситуации, когда Ваше Java приложение трещит по швам? В моём случае это случилось из-за нехватки доступной оперативной памяти. И, естественно, обнаружилась нехватка в самый неподходящий момент: на носу очередной долгожданный релиз, один из серверов остановлен для обновления кода и данных и реинкарнация старого кода уже невозможна, в ближайшие дни запланировано несколько совещаний и собеседований, что сильно отвлекает от процесса оптимизации - в общем, ЧП не прошло незамеченным. К слову сказать, сделай я правильный backup и экстренные работы по восстановлению жизнеспособности прошли бы гораздо более спокойно, но это была бы уже совсем другая история. Итак в моём распоряжении есть код, которому не хватает 15Gb оперативной памяти для нормального функционирования и очень длительный и дорогостоящий процесс запуска (около 5 часов), в ходе работы которого можно только сидеть со скрещенными пальцами и надеятся, что в этот раз заветные слова OutOfMemoryError не появятся в консоли удалённого сервера.
Не буду описывать всех ухищрений, которые пришлось проделать, чтобы восстановить остановленный сервер в течении трёх дней, но одним своим мини открытием поделюсь - boolean - это не тот тип данных, который Вы хотите использовать в высоконагруженных системах. Внимание вопрос:
Как Вы думаете, сколько памяти занимает boolean например на Ubuntu server x64?
Правильным ответом будет: неизвестно и зависит только от реализации JVM.
Рассмотрим распространённую Sun JVM и прочтем в спецификации виртуальной машины, что boolean типа в ней нет как такового, вместо него используется int! А это означает, что для хранения значения типа "да\нет" используется ровно 32 бита, независимо от архитектуры процессора. Правда в том же разделе мы видим, что произведена оптимизация для работы с массивами boolean, которые преобразуются в массив байт, что даёт прирост доступной памяти в 4 раза. И всё же платить за хранение нолика или еденички семью лишними битами - иногда просто кощунство и издевательство над серверами (особенно при размерах массивов в 500 миллионов элементов).
Спасением в таких случаях будет класс BitSet, который ведёт себя подобно массиву boolean, но упаковывает данные так, что для одного бита выделяется всего один бит памяти (с небольшими издержками для всего массива). BitSet хранит внутри себя массив типа long, а при запросе или установке значения определенного бита - высчитывает индекс нужного long и пользуясь побитовыми операциями и операциями сдвига производит вычисления над единственным битом.
Существует еще более интересная реализация BitSet, OpenBitSet - Apache реализация, которая используется для Lucene. Она гораздо быстрее, но упускает некоторые проверки, проводимые в оригинальном BitSet. Что использовать - решать Вам.
index
Friday, 9 October 2009
JMeter. Automated testing.
Tags:
java,
JMeter,
stress test,
testing
Тестирование. Я думаю, у многих это слово не вызывает приятных эмоций. Для разработчика это драгоценное время, потраченное на "ненужное" написание функциональных тестов, для тестера это проверка функциональности в кратчайшие сроки, для менеджера страх за приложение, который после беглого взгляда идёт в релиз.Почему так происходит? Рассмотрим простейшую ситуацию, которая не редко проиходит на просторах отечественного девелопмента. Предположим, разработку оценили в 5 дней, еще 3 дня запланировали на тестирование и день на сам релиз и подготовку окружения. Разработка опаздывает на день-полтора и, конечно же, сроки не сдвигаются, а страдает фаза тестирования. Причем каждая из трех сторон бермудского треугольника "разработчик-ПМ-тестировщик" давит на другую и каждая чем-то не довольна.
Сегодня я не хочу разбирать причины или правильные действия в таких ситуациях, я хочу показать преимущества автоматического тестирования и, в качестве примера, описать JMeter. Аналогов у данной программы множество, но к основным плюсам я могу отнести открытый код и как следствие лёгкую расширяемость под собственные нужды в случае необходимости, возможность распределенного тестирования, понятная документация, стабильность и множество полезных out-of-the-box компонент. К числу минусов я пожалуй отнесу квалификацию человека, пишущего тесты - дело в том, что более ли менее серьезные тесты должен писать человек, хоть немного программирующий и хотя бы поверхностно знакомый с XPath или RegExp.
Итак, автоматические тесты позволяют потратить Вам на тестирование меньшее количество времени при единожды написанных тестах под конкретную функциональность. Что можно создавать с помощью JMeter?
- интеграционные тесты. Функциональные тесты показывают Вам как работает каждая из компонент системы/приложения, но изменяя компонент, часто изменяют и тесты под него, не выясняя как это отразится на двух десятках приложений использующих компонент. Здесь на выручку приходят интеграционные тесты. Основным полезным инструментом JMeter здесь являются JMeter Assertions.
- нагрузочные тесты. Сколько активных пользователей могут одновременно работать при конвертации ста загружаемых изображений на серверной стороне? А при 10 000 изображений? А если быть более точным, то вопрос состоит в обнаружении кол-ва пользователей, которым данные отдаются с задержкой не более секунды, например. Здесь полезны JMeter Controllers, JMeter Timers для эмулирования пользовательских действий.
- стресс тесты. Данная группа тестов призвана обнаружить тот предел, при котором приложение не способно обслуживать запросы, выяснить поведение системы при предельных нагрузках и зарегистрировать возможные потери данных/уязвимости при наступлении критических ситуаций. Здесь поможет распределенное тестирование и всё что уже упоминалось ранее.
В данной статье я хочу остановиться на разного рода HTTP тестировании и некоторых нюансах, хотя ничто не мешает Вам использовать предоставляемую JMeter'ом возможность тестировать FTP, WebServices, DB, LDAP, JMS, Mail.
JMeter представляет собой приложение на Java, которое прекрасно запускается под любыми операционными системами (проверено собственноручно), как в GUI, так и в консольном режиме (что позволяет сделать выбор между визуализацией и производительностью). Ознакомиться с основными компонентами можно в отличной документации или просто запустив приложение и ознакомившись с контекстным меню. Как видно после первого запуска, в приложении есть 2 основных рабочих пространства:
- Test Plan - используется для создания собственно теста, как и следует из названия. Все основные операции проводяться здесь.
- WorkBench - используется для хранения временных компонент теста и некоторых важных не тестирующих компонент. Основное свойство - не сохраняется вместе с сохранением теста.
Варианты создания теста:
1. Создать тест вручную в пространстве Test Plan, пользуясь контекстным меню и примерами из документации.
2. JMeter прекрасно работает как Proxy и умеет записывать все выполняемые Вами запросы. Для такого способа создания теста Вам понадобиться добавить в WorkBench-> Add-> Non-test elements-> HTTP Proxy Server. Из настроек следует указать как минимум:
* Port. Это порт, который будет слушать JMeter. Я обычно ставлю 9090.
* Target Controller. Создайте новый Thread Group в Вашем Test Plan и выберите его в выпадающем списке Target Controller. Именно в эту группу будут записаны все запросы, прошедшие через прокси.
* URL patterns to Include/Exclude. Данный пункт позволит Вам указать c помощью RegExp, какие именно запросы, прошедшие через прокси, нужно сохранить в тест план. Советую для экспериментов попробовать сначала не заполнять данный пункт, а затем отфильтровать только ".*html" к примеру, чтобы почувствовать разницу.
Не забывайте перенаправить свой браузер на вновь созданный прокси (я, например, пользуюсь FoxyProxy для быстрого переключения режимов прокси в браузере) и стартовать/останавливать JMeter HTTP Proxy Server.
3. Создание теста программно. Дело в том, что Test Plan сохраняется в XML, который не сложно создать программно, если есть такая потребность.
О JMeter помимо документации:
- Помимо расширяемых модулей, поддерживает 2 скриптовых языка JavaScript и BeanShell. BeanShell - это полноценная скриптовая Java.
- Поддерживает Cookies, что позволяет авторизировать/регистрировать пользователей прямо в тесте.
- Практически в любом поле JMeter можно ввести переменную вместо значения. Вообще работа с переменными достаточно гибкая и удобная.
- Пользуясь PostProcessor'ами можно вычленять из ответа сервера информацию и сохранять её в переменных для последующих запросов.
- Есть помошь по функциям Main menu-> Options-> Function Helper Dialog
- В HTTP Sampler есть галочка "Retrieve all embedded resources from HTML files", которая бывает полезной для эмулирования полноценных пользовательских действий.
Горячие клавиши и неявные настройки.
- Если Ваш JMeter стартует за прокси сервером и ему нужен доступ наружу, Вам помогут ключи при старте -H <host> -P <port> -u <user> -a <password> -N <non-proxy-hosts>
- При включенном GUI и графических слушателях JMeter использует достаточно много ресурсов компьютера - для нагрузочного и стресс тестов используйте non-GUI опции запуска
- Распределённое тестирование управляется одним инстансом JMeter, который может распространить нужный тест, собрать результаты со всех нод, и производить некоторое управление распределённых нод.
- Ctrl+R - запустить тест
- Ctrl+. - остановить тест
- Ctrl+E - очистить результаты
Monday, 5 October 2009
CloudMade in action
Не так давно я рассказывал Вам про OpenStreetMap и его философию, а сегодня хочу рассказать о сервисах надстроенных над ним. Дело в том, что OpenStreetMap Foundation занимается поддержанием проекта, защитой лицензий, организацией комьюнити, подготовкой данных и предоставлением некоторого программного обеспечения, полезного для картографического сообщества.Всё ПО и данные распространяются под открытыми лицензиями (правда если вы модифицируете OSM данные в какой-либо формат, вы обязаны поделиться результатом преобразований с общественностью). В связи с этим фактом и неоспоримым качеством созданных карт существует достаточно большое количество проектов, призванных отшлифовать накапливаемое знание и предоставить конкурентноспособные сервиса.
CloudMade - компания, которая сумела запустить сразу несколько интересных проектов на базе OSM данных и при этом внести ощутимую лепту в развитие картографического сообщества.
- Поскольку это одна из ранних компаний использующих OpenStreetMap, она успела накопить и сформировать достаточно большое количество всевозможных фильтров данных (напомню, что OSM построена по принципу Wiki, а потому там иногда появляются дороги по экватору, подводные магистрали и т.п. вещи, которые Вы не увидите в продуктах CloudMade). Более того, все преобразованные данные доступны для публичного доступа.
- Разработаны всевозможные библиотеки для создания условий комфортного внедрения разработчиками карт от CloudMade.
- CloudMade занимается организацией Mapping parties, впрочем как и многие другие, но на мой субъективный взгляд гораздо более активно. А многие активисты CloudMade создают локальные комьюнити.
- Доступны карты как таковые, с большим спектром возможностей: построение маршрутов, геокодирование, векторными SVG картами, прекрасным редактором стилей, возможностью выгрузки построенного маршрута в GPX (формат, понятный для GPS устройств), равно как и загрузка карт на GPS устройства.
- В процессе финальных тестирований редактор OSM карт, который позволит пользователям более интуитивно справляться с задачей маппинга и автоматизировать некоторые трудоёмкие процессы.
- И многие другие приятные мелочи по ошибке или по другим причинам не включенные в данный обзор.
Будут вопросы - обращайтесь, расскажем что к чему.
Saturday, 26 September 2009
Мнимая единица
Tags:
imaginary unit,
logic,
quiz
"Доверяй, но проверяй" гласит народная мудрость и с ней нельзя не согласится. После прочтения задачки про прямоугольные треугольники решил вспомнить своё творение. Собственно о собственном авторстве я возможно преувеличил - раньше много занимался математикой, может где и подсмотрел, но многие слышали эту задачку от меня впервые, так что предложу её на суд более широкой общественности.
Всем нам еще в школе начинают рассказывать многие непреложные истины, на которых часто базируется понимание молодых людей о происходящем вокруг. Так, в конце школьного курса математики, мы получаем знание о использовании людьми всего мира мнимой единицы, для расширения знакомых нам ранее чисел до нового абстрактного уровня. Определение записанное в учебниках просто для понимания и указывает оно на то, что запретная ранее область - корень квадратный из отрицательных чисел - находит новую жизнь под покровительством мнимой единицы.
Итак, более формально:
Определение: Мнимой единицей называется корень квадратный из минус единицы и обозначается следующим образом 
Пояснения:
1. Первое равенство пришло из определения.
2. Второе образовалось из понимания того, что любое (подчеркиваю: любое) число разделенное на единицу равно само себе.
3. Далее имеем полное право умножить числитель и знаменатель на одно и то же число, отличное от нуля, в данном случае это число -1. При этом получаем в числителе единицу, а в знаменателе -1.
4. Корень из дроби равен корню из числителя поделенному на корень из знаменателя.
5. Корень из единицы есть не что иное, как сама единица.
6. Из определения можем смело заменить корень из -1 на i.
7. Домножим обе части равенства на i (на вполне законных основаниях, поскольку коэффициент домножения отличен от нуля):
Собственно вопрос: Какое из утверждений/преобразований не верно?
index
Wednesday, 2 September 2009
FreeMarker SimpleHash problem
Tags:
freemarker,
functionality,
hash problem,
number keys,
tools
Обработка шаблонов (Template processing) довольно часто встречается в нынешнее время в разнообразных проектах. Некоторые языки программирования даже совмещают написание логики с "шаблонизатором", что правда зачастую затрудняет поддержку логики. Я же в последнее время пользуюсь открытой библиотекой FreeMarker, которая не привязана к конкретным (особенно веб-ориентированым) технологиям и представляет удобный инструмент и богатый шаблонный язык разметки для Java проектов.
Подробнее о FreeMarker можно узнать по приведенной ссылке, а я сегодня хотел остановиться на некоторой особенности данной библиотеки. Работа с фримаркером начинается с настройки конфигурации, подготовки модели данных и собственно шаблона. Фримаркер - это инструмент отображения вашей модели, потому каждый объект модели оборачивается в специальный класс-обёртку, который не позволяет изменять модель данных из шаблона, а также закрывает доступ к небезопасным методам, которые могут кардинально изменить ход исполнения вашего приложения. Обёртками управляет инстанс ObjectWrapper класса.
Собственно проблема: java.util.Map оборачивается в обёртку, которая оперирует ТОЛЬКО ключами типа String. И если вдруг в Вашей модели попадается что-то вроде java.util.Map<Integer, SomeObject> - ну что ж Вам не повезло... Из данной ситуации есть выход - сменить ObjectWrapper (в поставке от FreeMarker их два) , либо написать свою реализацию, что немного затратно и неудобно. Смена фабрики обёрток ни к чему хорошему не приводит - появляются другие проблемы. Для знакомых с синтаксисом фримаркера:
Начинает возвращать не только ключи мапы, а и названия методов, что очень не удобно для итерирования и естественно выдаёт исключение в
Выход оказался вполне удобоваримый: исключительно настройками можно добиться нужного поведения:
index
Подробнее о FreeMarker можно узнать по приведенной ссылке, а я сегодня хотел остановиться на некоторой особенности данной библиотеки. Работа с фримаркером начинается с настройки конфигурации, подготовки модели данных и собственно шаблона. Фримаркер - это инструмент отображения вашей модели, потому каждый объект модели оборачивается в специальный класс-обёртку, который не позволяет изменять модель данных из шаблона, а также закрывает доступ к небезопасным методам, которые могут кардинально изменить ход исполнения вашего приложения. Обёртками управляет инстанс ObjectWrapper класса.
Собственно проблема: java.util.Map оборачивается в обёртку, которая оперирует ТОЛЬКО ключами типа String. И если вдруг в Вашей модели попадается что-то вроде java.util.Map<Integer, SomeObject> - ну что ж Вам не повезло... Из данной ситуации есть выход - сменить ObjectWrapper (в поставке от FreeMarker их два) , либо написать свою реализацию, что немного затратно и неудобно. Смена фабрики обёрток ни к чему хорошему не приводит - появляются другие проблемы. Для знакомых с синтаксисом фримаркера:
<#list map?keys as key>
${key}=${map[key]}
<#list>
Начинает возвращать не только ключи мапы, а и названия методов, что очень не удобно для итерирования и естественно выдаёт исключение в
${map[key]}Выход оказался вполне удобоваримый: исключительно настройками можно добиться нужного поведения:
this.configuration = new Configuration(); this.configuration.setDefaultEncoding("UTF-8");
this.configuration.setURLEscapingCharset("UTF-8"); this.configuration.setBooleanFormat("true,false");
this.configuration.setDateFormat( DateFormatUtils.ISO_DATETIME_FORMAT.getPattern() );
this.configuration.setWhitespaceStripping(true);
this.configuration.setLocalizedLookup(true);
this.configuration.setClassForTemplateLoading(this.getClass(), "/your/package/here");
if ( null != autoincludes )
this.configuration.setAutoIncludes(autoincludes);
BeansWrapper objectWrapper = BeansWrapper.getDefaultInstance();
objectWrapper.setStrict(true);
objectWrapper.setExposeFields(true);
objectWrapper.setSimpleMapWrapper(true);
this.configuration.setObjectWrapper(objectWrapper);
Собственно основное внимание должно быть уделено использованию BeansWrapper и objectWrapper.setSimpleMapWrapper(true);
После этого итерирование по мапе с ключами в виде чисел сводиться к немного изменённому синтаксису (обратите внимание на использование круглых скобок вместо квадратных):
<#list map?keys as key>
${key}=${map(key)}
<#list>
Subscribe to:
Posts (Atom)










