Последнее в категории Приложения

Да здравствует перл! Этот блог работает на перле, но писали его неизвестные мне люди Я тут зашел куда-то в админской части, и увидел массу комментариев, которые, оказывается, висят неодобренными. :-O 

Часть я пооткрывал, а часть (ай!) удалил. Перл + юзабилити часто так же несовместимо, как и многие другие продукты, созданный программистами.

И еще я забыл с собой зарядное устройство от телефона.

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

Презентация Анатолия Шарифулина на «Перлбурге».

XSLT::Dependencies

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

Небольшая предыстория.

Верстка сайта Microsoft сделана на XSLT. Разумеется, многие XSLT-файлы зависимы от других, и при верстке довольно часто приходилось пересохранять неизмененный основной файл, хотя изменения делались где-то в другом файле, который подключался. А это напрягало.

Студийный parser долгое время тоже не умел обновлять кеш зависимых XSLT-шаблонов. Это тоже напрягало (хотя более напрягал, конечно, сам parser).

По мере возможности я стараюсь кешировать разобранные и скомпилированные XSLT-файлы. На спане есть модуль XSLT::Cache, который, однако, не отслеживает зависимости. Недостаток призван компенсировать модуль XSLT::Dependencies.

use XSLT::Dependencies;
my @dep_list = XSLT::Dependencies->new->explore('myfile.xslt');

В списке @dep_list оказывается перечень всех файлов, которые прямо или косвенно подключены к файлу myfile.xslt.

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

В todo числится обучить модуль читать XSLT не только напрямую из файла, но и из уже разобранного дерева XML::LibXSLT.

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

state (1)

| Комментариев: 2

Из записок технического менеджера.

A

За последние несколько дней несколько раз рассказывал, что моя жена в свое время преподавала в университете C++ студентам-физикам. Сам-то я до сих пор испытываю нереализованное желание писать на этом замечательном языке — первом, в котором я досконально и по-взрослому разобрался.

В C++ есть модификатор static, который в применении к переменной означает, что ее значение не нужно забывать между вызовами функции.

Б

Мой коллега за последние несколько недель несколько раз коммитил код с модификатором state (правда, потом были и откаты этих правок). Сам-то я до сих пор ощущаю внутреннее желание найти еще сто тысяч применений новым фичам, появившимся в Perl 5.10, но чувствую, что досконально и по-взрослому это ощутят лишь через несколько лет.

В Perl 5.10 модификатор state делает то же самое, что и static в C++ — позволяет сохранять значение переменной между вызовами подпрограммы.

B

По-настоящему ощуить полезность новых фич получается только тогда, когда в них возникнет потребность в реальных примерах из ежедневной практики.

Сегодня как раз предоставился такой случай. Мне потребовалось выбрать случайную строку из большой базы данных. Разумеется, sort by rand() не подходит, а вот limit $N, 1 работает вполне быстро.

my $N = int rand $count;

Тут все понятно: чтобы узнать общее число записей $count, нужен еще один запрос (к тому же он с дополнительными ограничениями where). Вместо того, чтобы возиться с кешированием этой величины (memcached, BEGIN, etc.), достаточно поместить значение в статическую переменную, и вычислять ее, если она неопределена.

state $count;

unless ($count) {
    #
SQL-запрос select count(*)
}

my $offset = int rand $count;
#
SQL-запрос select ... limit $offset, 1

В файлик todo.txt заносится задача: использовать state совместно c defined-or (//).

Geo::Horizon

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

Сегодня можно было бы написать про Google Buzz, но Perl API к нему еще не создан :-)

Зато на спане есть полезный модуль Geo::Horizon, который позволяет вычислить расстояние до горизонта. Расстояние прямой видимости зависит от широты, на которой находится наблюдатель, и от его роста.

Например, когда в центре Москвы (на широте около 55°) снесут все гостиницы и старые здания, человек ростом 180 см (вставшего на цыпочки, чтобы компенсировать расстояние от глаз до макушки) сможет видеть на расстоянии около пяти километров (что, в общем, сходится с тем, что говорили на уроках природоведения).

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

say Geo::Horizon->new->distance(1.8, 55.7522); # 4794.73

При создании объекта типа Geo::Horizon возможно явно указать один из типов аппроксимации формы Земли, которые понимает модуль Geo::Ellipsoid, например:

my $gh = Geo::Horizon->new('WGS84');
say $gh->distance($height, $latitude);

Кроме того, возможно вычислить расстояние не по прямой, а по поверхности Земли. На высоте глаз человека разница будет неощутимой, но если смотреть с метеоплощадки телебашни в Ташкенте, то эта разница достигнет двух метров:

say $gh->distance(318, 41.345278);              # 63677.53
say $gh->distance_great_circle(318, 41.345278); # 63675.51

В фильме «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' к существующему. Незадача какая, сраный спан без аннотированных перекрестных ссылок.

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

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

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

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

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


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

Теперь настало время передвать более сложные аргументы, чем простые строки. Нет ничего проще — 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. Задачи параллелятся на ура, но важно понимать, что это имеет смысл только для тех задач, которые по своей природе проводят много времени в ожидании ответа, не тратя процессорное время локальной машины.

Страницы

  • img

Об архиве

Эта страница содержит последние записи категории Приложения.

Предыдущая категория — Презентации.

Следующая категория — Развлечения.

Смотрите новые записи на главной странице или загляните в архив, где есть ссылки на все сообщения.