пятница, 5 марта 2010 г.

[life.photo] Заложница с ножом у горла

Китаец взял свою сводную сестру в заложницы на улице города Вуксю (Wuxi):

Она была освобождена (даже без ранений), а он взят под стражу.

Снимок найден в очередном выпуске WSJ’s Pictures of the Day.

А вот как освобождение заложницы происходило:

Продолжение найдено почти там же.

четверг, 4 марта 2010 г.

[prog] О скорости упаковки/распаковки XML

Многие знают, а некоторые еще только догадываются, что использование XML для передачи данных – штука недешевая. Скорость упаковки/распаковки XML в несколько раз меньше различных форм бинарной сериализации. Но вот во сколько раз?

По работе пришлось заняться этим вопросом и вот что удалось с ходу найти в Интернете:

An XML Alternative for Performance and Security: ASN.1 – небольшая статья от 2004 года, в которой сравниваются скорости работы ASN.1 и XML. В некоторых случаях скорость декодирования XML на 1000% медленнее скорости декодирования ASN.1 (речь, насколько я понял, идет о подписанных сообщениях).

Use of ASN.1 Encoding Rules for Binary XML – 37-ми страничная презентация от Objective Systems Inc., в которой приводятся результаты нескольких замеров производительности. Впечатлил такой результат: на сериализацию 10000 сообщений (объем в ASN.1 BER – 125 байт, объем в XML – 868 байт) потребовалось: для ASN.1 BER – 53 миллисекунды, для XML – 139 миллисекунд. А для десериализации: ASN.1 BER – 58 миллисекунд, тогда как для XML – 1228 миллисекунд.

Investigating Performance of XML Web Services in Real-Time Business Systems – практически совсем свежая статья о том, какие существенные накладные расходы привносит XML-формат в SOA и как можно с этим бороться.

Сам я сегодня провел маленький эксперимент по моделированию своей задачи: некий узел должен принимать несколько тысяч сообщений типа A и формировать несколько тысяч сообщений типа B. Так вот у меня для двоичного формата (по принципам TLV из ASN.1 BER) получалось время ~40 миллисекунд. А для XML-формата – ~250 миллисекунд (в качестве XML движка использовалась библиотека POCO, не исключено, что с libxml2 время было бы меньше). Что интересно, в моем случае сериализация XML потребляла больше времени, чем десериализация (возможно, из-за слишком тривиальной реализации теста).

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

Так же я разыскиваю замеры производительности (в особенности сравнения производительности) различных message-oriented middleware продуктов (вроде IBM WebSphere MQ, SonicMQ, FUSE Message Broker, TIBCO Rendezvous, FioranoMQ и т.д.) Был бы признателен за помощь в поиске публично доступных материалов на эту тему.

среда, 3 марта 2010 г.

[prog.c++] Пустой массив в структуре

Когда-то давным-давно, изучая программирование под Windows, встречал иногда вот такой фокус:

struct some_struct_t
   {
      int field_1;
      ...
      int field_N;
      char last_field[];
   };

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

char raw_data[ SOME_LIMIT ];
read_data( raw_data, sizeof( raw_data ) );
const some_struct_t * data =
      reinterpret_cast< const some_struct_t * >( raw_data );
for( size_t i = 0; i != data->field_K; ++i )
   if( XXX == data->last_field[ i ] )
      ...

Такой хак использовался когда-то в C, а потом достался в наследство C++. Ну и ладно бы, никогда к нему не прибегал. А на днях пришлось объяснять человеку, что когда он пишет вот так:

struct info_t
   {
      char * name[];
   };
info_t info;
for( size_t i = 0; i != ...; ++i )
   info.name[ i ] = new char[...];

то это, мягко говоря, не совсем правильно. Поскольку память под name никто не выделял, но наглым образом использует.

При этом я открыл для себя интересную штуку: оказывается, C++ компилятор под поле info_t::name вообще не выделяет места! Т.е. я думал, что при такой записи в info_t под поле name будет отведено место на один char*. Но нет! В Visual C++ 2003-2008 размер всей структуры info_t – всего один(!) байт (что и понятно, поскольку объектов с нулевым размером быть не должно). А вот в GCC 4.3.2 из cygwin-а размер info_t все-таки нулевой.

Вот такие дела. Век живи – век учись, дураком помрешь ;)

[comp.modem] Мой Acorp W422G приказал таки долго жить

Не смотря на недавно проведенный ремонт, мой ADSL модем Acorp W422G все-таки перестал нормально работать. Не знаю, что точно произошло (был на работе), но в один прекрасный момент модем перестал обнаруживать DSL-линию. Как через ASDL-сплиттер, так и без оного. После обращения в БелТелеКом линия обнаруживаться начала, но скорость была крайне низкой и связь была ненадежной. Разбирательство со специалистами БелТелеКома показало, что у нас очень низкий уровень сигнала. И было не понятно, по чьей именно вине.

В конце-концов, мы взяли ADSL-модем с WiFi-ем в самом БелТелеКоме (благо бесплатно и сейчас у них такие модемы есть), с ним все заработало. Новый модем быстро нашел DSL-линию и связь держит стабильно. А старый Acorp мигает-мигает огоньками, но без толку.

Видимо, опять возникли какие-то неполадки в модеме, на этот раз в модуле ADSL. Но чинить его уже желания нет :)

Так что Acorp W422G был вполне себе хорошим, неприхотливым девайсом с хорошими возможностями. Но проработать смог всего год. Что мало, я считаю. Поэтому никому сию модель рекомендовать не буду.

Кстати, рекомендация для тех, кто сам будет настраивать модем “Промсвязь M-200 A” (в девичестве ZTE) в режиме router-а: имя сервиса (которое предшествует имени пользователя и пароля в диалоге настроек) нужно оставлять пустым. Я изначально задал его и долго курил, почему же меня не пускает в Интернет :)

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

вторник, 2 марта 2010 г.

[prog.c++.bicycle] Еще один трюк в отсутствии rvalue references

В C++0x планируется добавление интересной штуки под названием rvalue references, которая должна убрать изрядную часть накладных расходов в C++ программах. Но пока C++0x не принят, приходится жить без rvalue references и изобретать разные вспомогательные велосипедики.

Первый, под названием temporary_object_ref, я начал использовать года полтора назад. Штука тривиальная и, временами, полезная. Но не всегда. Представим себе, что у нас есть объект, конструктор которого получает три сложных аргумента:

class demo_t
   {
   private :
      std::string m_destination;
      std::string m_source;
      std::list< std::string > m_hints;

   public :
      demo_t(
         const std::string & destination,
         const std::string & source,
         const std::list< std::string > & hints )
         :  m_destination( destination )
         ,  m_source( source )
         ,  m_hints( hints )
         {}
   ...
};

Если мы используем только этот конструктор, то мы всегда вынуждаем объект demo_t копировать значения аргументов. Даже в случаях, когда аргументами являются временные объекты:

std::string destination = domain + "/" + subject + "/" + timestamp;
std::list< std::string > hints;
hints.push_back( "lifetime: default" );
hints.push_back( "priority: default" );

demo_t demo( destination, source, hints );

В этом случае временные объекты destination и hints после объявления demo не нужны. И было бы хорошо, если бы при инициализации demo их значения перешли бы объекту demo (та самая move semantic из C++0x).

Этого можно было бы достичь с помощью temporary_object_ref, если добавить в demo_t еще один конструктор:

class demo_t
   {
   ...
   public :
      ... // Остальные конструкторы.
      demo_t(
         temporary_object_ref_t< std::string > destination,
         const std::string & source,
         temporary_object_ref_t< std::list< std::string > > hints )
         :  m_source( source )
         {
            destination.writeable().swap( m_destination );
            hints.writeable().swap( m_hints );
         }
   ...
};

...

demo_t demo(
      make_temporary_object_ref( destination ),
      source,
      make_temporary_object_ref( hints ) );

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

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

class demo_t
   {
   ...
   public :
      demo_t(
         const_or_swappable_t< std::string > destination,
         const_or_swappable_t< std::string > source,
         const_or_swappable_t< std::list< std::string > > hints )
         {
            destination.apply_value( m_destination );
            source.apply_value( m_source );
            hints.apply_value( m_hints );
         }
   ...
};

...

demo_t demo(
      swappable_object( destination ),
      const_object( source ),
      swappable_object( hints ) );

Весь фокус в простом шаблоне const_or_swappable_t (код которого будет приведен ниже). Если объекту const_or_swappable_t передается константный аргумент, то в своем методе apply_value он выполняет его копирование. Если же аргументом является временный объект – то в apply_value вызывается swap. Тип аргумента (константный или временный) указывает программист посредством вспомогательных функций const_object и swappable_object.

Disclaimer. Пока это решение на практике я еще ни разу не применил. Самым явным его недостатком является то, что при его использовании сначала вызываются конструкторы по умолчанию для атрибутов класса, а только затем отрабатывают apply_value. Это так же лишние накладные расходы. А так же нельзя инициализировать подобным образом атрибуты-константы.

А вот код const_or_swappable_t с необходимыми вспомогательными функциями:

struct constant_object_tag {};
struct swappable_object_tag {};

template< class T >
class const_or_swappable_t
   {
      union {
         const T * const_ptr;
         T * swappable_ptr;
      } m_ptr;
      bool m_is_const;
   public :
      const_or_swappable_t( constant_object_tag, const T & o )
         :  m_is_const( true )
         {
            m_ptr.const_ptr = &o;
         }
      const_or_swappable_t( swappable_object_tag, T & o )
         :  m_is_const( false )
         {
            m_ptr.swappable_ptr = &o;
         }

      void apply_value( T & to ) const
         {
            if( m_is_const )
               to = *(m_ptr.const_ptr);
            else
               m_ptr.swappable_ptr->swap(to);
         }
   };

template< class T >
const_or_swappable_t< T > const_object( const T & o )
   {
      return const_or_swappable_t< T >( constant_object_tag(), o );
   }

template< class T >
const_or_swappable_t< T > swappable_object( T & o )
   {
      return const_or_swappable_t< T >( swappable_object_tag(), o );
   }

понедельник, 1 марта 2010 г.

[work] Советы соискателям

Казалось бы, столько кругом говорят о том, как правильно писать резюме… Ан нет, видимо, мало. Поэтому я позволю себе дать несколько советов соискателям (на должность программистов, по крайней мере).

Прежде всего запомните: ваше резюме приходит к руководителю, который ищет себе подчиненных. Не важно, будет ли это менеджер проектов или тим-лидер – для вас это начальник. Начальству нужны подчиненные для того, чтобы переложить на них часть своей головной боли работы. А посему, если ваши резюме уже увеличивают этот объем еще на этапе знакомства с ними, то ваши шансы, соответственно, уменьшаются.

Как вы увеличиваете объем работы своего потенциального начальника? А вот так:

1. Присылаете свои резюме с таких e-mail-ов, по которым невозможно понять ни имя, ни фамилию. Когда я вижу письмо от “Бубль-гум <dodik@gmail.com>” я не могу вспомнить, кто это и зачем он мне пишет. Накануне я запомнил, что мне присылал резюме Иван Иванов и я задал ему несколько вопросов. И жду ответов от Ивана Иванова, а не от Бубль-гума. Вспомнить тождество между Ивановым и Бубль-гумом – это лишняя работа, которую я делать не хочу.

2. Расставляете какие-то условные баллы самому себе для указания степени владения инструментами. Вроде такого:

Владение инструментами (1 – начальный уровень, 2 – средний уровень, 3 – хороший уровень, 4 – отличный уровень):

MS SQL Server: 2
Visual C++: 3
MFC: 4
… (и далее перечень из десятка-другого названий)

Тут сразу несколько проколов.

Во-первых, я вынужден делать лишнюю работу по переводу циферок в какую-то качественную оценку. Вот вижу я тройку в графе Visual C++ и что? Это по 5-ти балльной шкале или 10-балльной? Или это годы использования? Еще круче, когда такие записи оформляются в виде таблички с несколькими столбцами – баллы за уровень знания, годы использования, количество проектов и т.д. При этом список технологий не маленький, и шапка таблицы оказывается где-то на предыдущей странице, поэтому с ходу не поймешь, что обозначают последовательности вида “3 4 5”. Чтобы разобраться с этим, мне приходится делать лишнюю работу, которую делать я, естественно, не хочу.

Во-вторых, ваши собственные баллы мне ничего не говорят. Я сам себя временами оцениваю как хорошо знающего C++. До тех пор пока не встречаю на форумах или у своих коллеги простые вопросы, на которые не могу сразу ответить. Поэтому, когда я вижу оценку от соискателя в 4 или 3 балла, мне приходится напрягаться, чтобы сделать какие-то “поправки на ветер” – мол, если человек работает на C++ три года и выставил себе оценку в 4 балла, то… Это лишняя работа, я не хочу ее делать. Поэтому пишите просто опыт в годах. Ну или давайте какие-то объективные оценки, вроде результатов BrainBench-а, если таковые у вас есть (хотя лично мне на такие пенисомерки оценки наплевать).

3. Перечисляете в своем резюме такие технологии, которые не имеют отношения к требованиям вакансии. Если вакансия для “С++ разработчика” без требований знания .NET-а, то не нужно вписывать в резюме C# и LINQ – мне это пофигу и я вынужден тратить время на выискивание нужных мне технологий в вашем непозволительно длинном перечне. Сюда же идут пассажи по поводу наличия водительских прав, желания ездить в командировки и порода любимой собачки т.п.

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

PS. Еще лично у меня есть предубеждение по поводу красочно оформленных Word-овских документов, которые присылают в качестве резюме. Лично мне это не нравится (особенно когда все это сочетается с тремя вышеизложенными недостатками), хотя объективных возражений против Word-а я придумать не могу.

Короче – будьте проще.

[life.cinema] Очередной кинообзор

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

Я. Какой-то укуренный фильм про каких-то укурок.

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

Жена путешественника во времени. Добротно сделанная мелодрама с оригинальным фантастическим сюжетом. Сам я поклонником мелодрам не являюсь, но жене фильм понравился.

Возмездие. Качественно сделанный фильм. Отличная игра Мэла Гибсона. Но мне показался слишком затянутым и, местами, черезчур запутанным.

Наша Раша: Яйца судьбы. Вполне нормальная попытка сотворить из юмористического шоу "Наша Раша" комедию. Местами смешно, местами нет, чаще нет. Фраза "А я наказываю, жестоко наказываю", похоже, войдет в мой словарь так же плотно, как и "Да ты успокойся!" Впечатления о фильме были бы гораздо хуже, если бы не комментарии Сергея Юрьевича Теплакова под финальные титры ;)

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

Легион. Ерунда – нет ни серьезного сюжета, ни нормального экшена, ни спецэффектов, ни актерской игры.

Формула любви для узников брака. За исключением последних 20 минут (очень предсказуемых и слащаво-приторных) вполе нормальная коммедия.

Пила 6. Как всегда качественно снятое мочилово и расчлененка. Сюжет абсолютно вторичный или даже третичный. Но в конце достойно сделан задел для Пилы 7.

Посылка. Очень даже ничего. Посмотрел с удовольствием. Хотя чего-то мне в фильме не хватило, что-то там не срастается (но что не знаю), так что не шедевр, к сожалению.

Наперегонки со смертью. На удивление неплохой фильм оказался. Простенько и со вкусом. Далеко не "Карты, деньги и два ствола", но я посмотрел с удовольствием.

Из Парижа с любовью. Легкий, динамичный и веселый боевик, который нужно смотреть, выключив мозги.