четверг, 11 февраля 2010 г.

Синхронизация доступа: on Type or not on Type

Сегодня на собеседовании задал кандидату вопрос о том, как реализовать Singleton в C#. Сначала он предложил самый простой вариант (не thread safe) и в ходе дальнейшего обсуждения (“а почему так? а что если у нас многопоточное приложение? и что делать в этом случае?” и т.п.) предлагается вариант с блокировкой (внимание):

lock(typeof(MySingleton)) { …

В этот момент я подумал: “однако…”. На вопрос: “А почему так?” кандидат ответить затруднился, сославшись на некую статью, читаную им когда-то на просторах интернета.

На первый взгляд идея выглядит подкупающе свеж: не нужно держать отдельный объект, по которому идет синхронизация, все просто и элегантно. Даже MSDN подтверждает, что объекты класса Type уникальны (т.е. в своем роде синглтоны):

A Type object that represents a type is unique; that is, two Type object references refer to the same object if and only if they represent the same type.

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

Note:

In multithreading scenarios, do not lock Type objects in order to synchronize access to static data. Other code, over which you have no control, might also lock your class type. This might result in a deadlock. Instead, synchronize access to static data by locking a private static object.

Так что “увы и ах” - не судьба (даром что выглядит элегантно). И не забываем о пользе чтения документации.

HTH,

AlexS

среда, 3 февраля 2010 г.

Первые впечатления от StreamInsight (aka Complex Event Processing от Microsoft)

В состав SQL Server 2008 R2 релиз которого намечен на май этого года, входит технология StreamInsight (официальная страница и блог). Несмотря на очевидную ассоциированность, к SQL Server-у эта технология не имеет практически никакого отношения – кроме того факта, что их “положили в одну коробку”.

StreamInsight – это попытка Microsoft выйти на новый для себя рынок Complex Event Processing (в конце поста есть несколько ссылок на информацию о других игроках). Общее описание идея очень сильно напомнило мне системы обработки сообщений: скорее всего из-за наличия потоков, очередей, обработки и прочих схожих концепций. Ключевым, на мой взгляд, является слово “Complex”: предполагается, что мы производим над входным потоком событий некоторые нетривиальные манипуляции, которые позволяют нам осуществлять анализ этого потока в реальном времени (точнее “с известной задержкой”, поскольку зачастую речь идет об операциях, проводимых на каком-то [скользящем] окне наблюдений). Технология доступна пока только для предварительно просмотра, скачать можно отсюда. Дистрибутив компактен (около 10 Мб) и содержит неплохую подборку примеров и обзорную документацию. Последняя, однако, не настолько актуальна, как MSDN.

В обзорной документации все описано простым и понятным языком:

  1. Определяем входной поток событий.
  2. Задаем механизм обработки - на самом деле Linq-запрос, в котором можно использовать некоторые специфичные для потоков событий функции (вроде обращения к “окну”).
  3. Задаем характеристики выходного потока - поток результатов выполнения запроса из п.2 на входном потоке событий.

Обещается масштабируемость “куда хочешь” и параллельная обработка “как хочешь”.

В ходе попытки самостоятельно реализовать приложение, использующее эту технологию, пришлось столкнуться со следующими проблемами:

  • Для того, чтобы “воткнуть” поток в CEP Engine (который занимается вычислениями/обработкой) необходимо реализовать InputStreamAdapter (который выполняется в контексте того же процесса, который выполняет CEP Engine). Этот адаптер на самом деле является конечным автоматом (aka State Machine). Состояния вроде бы описаны, но машина далеко не так проста, как хотелось бы. Причем со всеми этими переходами приходится быть чрезвычайно аккуратным, ибо в примерах есть грозные предупреждения вида “если не сделать вот этот ‘финт ушами’, то в CEP Engine будет утечка памяти”. Таким образом, для реализации простейшего адаптера приходится писать довольно много не относящегося к делу кода. Аналогичная ситуация и с выходными потоками – тот же конечный автомат и те же проблемы: довольно много сервисного кода на ровном месте.
  • Не до конца понятен механизм типизации событий: она (типизация) вроде бы заложена в сам поток (который является generic-классом), но отсутствует в адаптере потока (который, собственно, и “производит” поток для CEP Engine).
  • Пока не совсем понятно, как все-таки эта штука масштабируется и какая у нее пропускная способность.
  • Также не очень ясно, насколько сложный анализ можно производить: в расчете простейших агрегаций особого (революционного) смысла нет, а вот относительно более сложных расчетов возникают вопросы: как их “скрестить” с Linq? какую величину окна сможет безболезненно (для производительности) сохранять CEP Engine? Ответов я пока не нашел.

Однако “попилим еще” и будет видно. Глядишь, к моменту выхода (или к версии 2 ;-) ) станет более понятно что к чему.

Где еще можно об этом почитать:

HTH,

AlexS