Template::Semantic

| Нет комментариев

Один из бешеных японцев™ — Наоки Томита — сегодня опубликовал на спане интересный модуль Tempalte::Semantic, один из немногих yet another-шаблонизаторов, на который стоит обратить внимание.

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

Например, чтобы вывести заголовок на страницу, сначала создаем HTML-заготовку:

<html>
    <head>
        <title></title>
    </head>
</html>

А затем описываем правила а-ля CSS:

use v5.10;
use strict;
use Template::Semantic;

say Template::Semantic->process(
    'title.html',
    {
        'html title' => 'My Title',
    }
);

Эта программа напечатает HTML-код с подставленным заголовком:

<html>
    <head>
        <title>My Title</title>
    </head>
</html>

Fantastique!

Описания с CSS-селекторами или XPath-адресами допустимо создавать и более сложной структуры, в том числе с вложенными хешами и списками (последние позволяют размножать фрагменты HTML-шаблонов).

Примеры наглядно описаны в документации модуля, а кроме того собраны в отдельном файле Template::Semantice::Cookbook.

Why Perl?

| Нет комментариев

На этой неделе в рассылке Moscow.pm я задал простой вопрос: как показать начинающим программистам сильные стороны Perl?

В итоге получилось большое обсуждение на листе, где в том числе вспомнили картинку про создание мира, кросспостинг (позже удаленный) на ru_perl с руганью в комментариях в частности о том, надо ли лукавить перед студентами, сгущая краски, пост на ru_perl о том, что студентам надо преподавать не Perl, а Java и XML и перепост перепоста с интересным обсуждением в комментариях о нишах языков.

Stay tuned, епта.

В фильме «13-й этаж» описывалась ситуация, когда смоделированный в компьютере мир создал свой собственный искусственный мир. При работе с Gearman можно столкнуться с задачами, которые в свою очередь удобно разбивать на части и отдавать на обработку следующим воркерам. Причем передача возможна в том числе тому же методу воркера, из которого она инициирована.

Вот пример. У нас есть сервис, отыскивающий по названию город в базе данных. Атомарная работа — поиск города — задача, вынесенная в отдельный воркер. При этом воркер умеет самостоятельно обрабатывать запрос, состоящий из нескольких слов:

my @words = $request =~ m{(\w+)}g;
for my $word (@words) {
    place_locality_search_word($word, $response);
}

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

Важно не забывать, что такая схема требует наличия как минимум двух воркеров (один может быть и занятым при получении начального задания).

На картинке — тестовый результат работы такого рекурсивного механизма для запроса со списком городов с ближайшими Perl-мероприятиями (софия екатеринбург амстердам москва киев vlorë).

P. S. Пока не стал коммитить такое решение :-)

Geo::Ellipsoid

| Нет комментариев

Из записной книжки программиста.

Январь

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

Когда Яндекс открывал свои «Самолетики», они ввернули в заметке в их корпоративном блоге какое-то умное слово — ортодромии. Ну явно для того, чтобы поумничать. Кто же не знает, что ортодромия — это не про нашу Землю, это лишь кратчайший путь на поверхности сферы вращения. Мне-то нужно найти конкретный модуль по употребимому английскому названию и именно для Земли. Это название — great circle. Ищем.

На спане быстро нашлась пара модулей, про один из которых в первой же строке документации написано, что он broken, а второй вроде ничего. Разве что название космической длины. Не страшно, берем в дело, радуемся и закрываем задачу.

Февраль

Стало скучно, что мы тут уже месяц считаем расстояние по ровненькому шару, а Украина до сих пор не выбрала президента. Что же там есть на спане еще? Йоу! Есть модуль Geo::Ellipsoid, и в нем с десяток разных формул, по которым описывают форму Земли. Хочу.

Так, что нужно? Интерфейс странноват, но понятен. Попробую на старом примере, посчитаю расстояние от Москвы до Киева. Как хорошо, что в папке /test у меня все это сохранилось, не надо заново искать координаты.

use v5.10;
use strict;
use Geo::Ellipsoid;

my @moscow = (55.7522, 37.6156);
my @kiev = (50.4333, 30.5167);

my $geo = new Geo::Ellipsoid(
    ellipsoid => 'WGS84',
    units => 'degrees',
    distance_units => 'kilometers'
);

my $dist = $geo->range(
    $moscow[0], $moscow[1], $kiev[0], $kiev[1]
);
say $dist;

В очередной раз напрягся, восстанавливая в памяти, что из longitude и latitude широта, а что — долгота, но вроде не перепутал и получил ответ, поохожий на правду. С GIS::Distance было 757 километров, с Geo::Ellipsoid — 759. (А оно должно было стать больше или меньше? Хотя какая разница, если все равно города на разной высоте относительно моря.)

Закоммичу, пожалуй.

Три минуты спустя

Коллега, прочитавший пришедший в почту дифф коммита, пишет: «Хм, а GIS:Distance::Formula::GeoEllipsoid?». Что это? Позырю. Блядь, я же забыл, что GIS::Distance может еще считать и по эллипсоиду. Читал же, когда его пробовал в прошлый раз. GIS::Distance это обертка, которая делегирует все расчеты другим модулям. Вместо того, чтобы приделывать новый модуль, можно было бы просто указать параметр ellipsoid => 'WGS84' к существующему. Незадача какая, сраный спан без аннотированных перекрестных ссылок.

30 января в Софии прошел второй болгарский Perl-воркшоп. Первое мероприятие было проведено ровно год назад, 31 января 2009 года.

На этот раз посетителей и докладов было поменьше, но сам воркшоп от этого ничуть не пострадал. (Хотя, надо вспомнить офлайн № 17 Moscow.pm, размывший понятия воркшопа и встречи pm-группы.)

Воркшоп помогали организовывать Бойчо Бойчев и Мариан Маринов, который регулярно проводит конференцию по открытому ПО OpenFest, приезжал в Москву рассказывать про Gluster, и возил Джонатана смотреть окрестности Софии.

Выступлений было три, но все они получились продолжительными :-) Мариан рассказал про AnyEvent, Петар Шангов — про Catalyst, я — про Gearman.

На социальную часть людей пришло чуть ли не больше, чем на основную. Выяснилось, что случился локальный эпик фейл с анонсом. Каждую последнюю пятницу месяца в Софии проходит какое-либо IT-мероприятие, и обычно оно начинается в 13 часов. На одном из местных линуксовых сайтов анонс воркшопа висел под статической шапкой, где и было указано это время, хотя наше мероприятие началось в 11. На шапку посмотрели, а текст анонса не почитали.

Интересная деталь: среди участников (по крайней мере, социальной части :-) были отец и сын. Два поколения, старший — Пламен и младший — Николай. Отец, к тому же, говорил по-русски и много рассказал про Софию, про скользкие желтые кирпичи на центральной — «Желтой» — площади, про бывший проспект Ленина и нынешний Царя-освободителя, а заодно про македонцев, ментлитет итальянцев, англицизмы и русизмы в болгарском языке.

На следующий год мы планируем провести третье мероприятие про Perl в Болгарии, но сделаем это вместе с одним из регулярных IT-мероприятий в Софии.

В минувшую суботу показал болгарам, что такое Gearman :-)

Интересно, что про Gearman я впервые услышал от человека, пришедшего на собеседование в РИА Новости. Мы даже попросили тогда записать это слово на бумажке. Потом мы с Толей Стояновским пробовали использовать его для распараллеливания задач по сборке веб-страницы, но в итоге остановились на том, что будем использовать его «родственника» — другой продукт того же автора, TheSchwartz, который хранит задачи в базе данных, — и не для веба, а для служебной задачи «слива» новостей на серверы партнеров.

В то время Gearman-сервер был полностью написан на перле. Сегодня существует реализация на C, которую, очевидно, и нужно применять, и более того, созданы клиенты на C, Python, Java, C#, PHP и даже MySQL и PostgreSQL.

Заставить стабильно работать приложение с использованием Gearman, несмотря на всю простоту идеи и интерфейса, — может потребовать большого терпения. Тем не менее, это стоит попробовать и использовать. На голландском Perl-воркшопе в начале марта я хочу показать продолжение презентации, в которой расскажу о том, как использовать Gearman для веба.

Распределение задач с помощью Gearman. Январь 2010.


P. S. Очень удобный способ делать презентации: сначала месяц мусолишь в блоге по крохам тему, а потом на утро перед выступлением собираешь все вместе :-)

Вчера двухсполовинойлетний Даниил Андреевич нарисовал вот такую штуку.

Чтобы снять неясность о том, что родитель увидел в рисунке своего ребенка, привожу рядом другую картинку — логотип с pm.org.

Теперь настало время передвать более сложные аргументы, чем простые строки. Нет ничего проще — use Storable.

Перед тем, как передать задачу воркерам, упаковываем аргументы:

my $c = 0;
for (qw (red orange yellow green blue violet)) {
    $tasks->add_task(
       'search' => freeze([$c++, "$_ $text"]),
       {
         on_complete => \&search_completed
       }
    );
}

А внутри функции воркера — распаковываем:

my $request = thaw($job->arg);
my $result = MySearch::search($request->[1]);

После того, как получен результат, с ним потребуется произвести те же манипуляции, но в обратную сторону: заморозить (freeze) результат, вернуть серверу gearmand, а на клиентре — растопить (thaw).

Правда или нет, но передача данных от воркера в вызывающую задачу — глючит (особенно в Gearman::XS::Worker), да и бесконечные freeze/thaw только уродуют код. Намного удобнее, если воркер не будет ничего возвращать, а вместо этого складировать свои результаты в общее хранилище (например, в базу данных), доступное вызывающему приложению.

Переделка скрипта для работы с Gearman весьма проста, если решение задачи запрограммировано таким образом, чтобы у нее были только вход и выход :-) В случае со вчерашним примером функция поиска, помещенная в воркер, состоит из двух строк:

sub search {
    my $job = shift;

    return MySearch::search($job->arg);
}

Клиентский код несколько усложняется: сначала необходимо создать пул задач, а затем дождаться их выполнения:

for (qw (red orange yellow green blue violet)) {
    $tasks->add_task(
        'search' => "$_ $text",
        {
            on_complete => \&search_completed
        } 
    );
}
$tasks->wait;

Сбор данных по окончании каждой задачи тоже крайне прост:

sub search_completed {
    my $result = shift;
   
    $html_result .= $$result;
}

Теперь осталось запустить с десяток отдельных воркеров, и скорость работы тестового скрипта возрастает на порядок: последовательные запросы на поиск картинок шести цветов зарубежной радуги завершались за 1-3 секунды, после модернизации — за 0,1-0,6. Задачи параллелятся на ура, но важно понимать, что это имеет смысл только для тех задач, которые по своей природе проводят много времени в ожидании ответа, не тратя процессорное время локальной машины.

На болгарском Perl-воркшопе я хочу немного рассказать о том, как на практике обрабатывать задачи, используя Gearman.

Один из примеров — последовательная трансформация кода: сначала цикл, потом параллельный вызов нескольких воркеров, затем попытка использовать внутри воркеров общие данные.

Отдельная задача минимальна: для заданного запроса $text найти на гугле несколько картинок разного цвета. В первом случае, когда используется цикл, работает такой код:

for (qw (red orange yellow green blue violet)) {
    $html_result .= MySearch::search("$_ $text");
}

Я хочу показать, как эти запросы распараллелить, передав их разным воркерам, работающим на разных машинах. А следующий шаг — научить независимые воркеры использовать общие данные, используя либо memcached, либо дополнительный неблокирующий воркер.

Страницы

  • img