четверг, октября 16, 2008

Между тем, MS, похоже, наваяла свой собственный клон Erlang'а, обозвав его 'Concurrency and Coordination Runtime', но запрятала его так, что заметил один Рихтер. Конкретно, в Microsoft Robotics Studio.
Наличествующие сущности:
- Dispatcher - набор потоков, в которых исполняется код.
- DispatcherQueue - очередь заданий, исполняемых потоками диспетчера в режиме round-robin.
- Port - типизированный вход для отправки сообщений на обработку. Порты могут группироваться в PortSet'ы (например, для связывания с операциями, результатом которых может быть значениие либо exception).
- Arbiter - собственно, обработчик сообщений, помещающий при срабатывании соответствующую задачу в очередь. Т.е. Арбитры напоминают оператор receive в erlang'е, но обладают большим разнообразием: есть арбитры для получения одного/нескольких сообщений с одного порта, обработки событий с любого или со всех портов из набора (т.е. объединение событий по ИЛИ/по И).
Что особенно приятно, все это довольно очевидным связывается с более традиционной Asynchronous Programming Model (которая "BeginXXX/EndXXX").
Надо будет эту штуку попробовать, создается впечатление, что с ее помощью удобно реализовывать многопоточные сервисы... =)

четверг, сентября 04, 2008

Все уже написали, один я остался.
Исправляюсь.
Пользовательские впечатления:
- красивенько (и интерфейс, и особенности рендеринга, типа подсветки активного элемента HTML);
- шустренько;
- маловато функциональности для меня (я привык к RSS-агрегатору, почтовому клиенту и детальным настройкам в Опере), но jedem das seine (, например, доволен). Опять же, предполагается, что почту и RSS люди будут юзать гугловские =);
- пока глючно (чего стоит падение от сочетания символов %:);
- не проникся идеей ресайза одних только шрифтов;
- проверка орфографии для русского языка отстойна (или "отстой на", как она сама предложила =))

Технические впечатления:
- Необычен (но достоин уважения) подход по выделению закладок в отдельные процессы-sandbox'ы (хотя от вышеупомянутой баги не защищает ;));
- памяти кушает больше, чем Опера
- напрягает периодический ломёж браузера на гугловские сайты (видимо, с сообщениями о перемещениях пользователя, пока не понял);
- напряг пункт в EULA насчет передачи всего сформированного контента в длинные руки гугла, но говорят, что этот пункт отменен;

Мнение:
Цель создания этой программы, скорее всего, все-таки не создание еще одного FLOSS-браузера, а построение клиентской части гугловской платформы разработки Web-приложений (в особенности, работающих на Google App Engine). Т.о., Chrome конкурирует не с IE/Firefox/Safari/Opera, а с Silverlight/JavaFX/AIR. Об этом говорит наличие встроенного отладчика JavaScript и инспектора HTML, использование Gears, упор на быстродействие движка JS.
Такое вот ИМХО.

четверг, августа 28, 2008

работа с C# Expression trees

Иногда стопроцентно известна сигнатура конструктора класса (соглашение такое, скажем), но сам класс неизвестен.
Например, потому что этот класс - параметр дженерик-метода. А у дженериков в качестве ограничения типа можно задать только конструктор без параметров, что не гуд.
Тогда приходится использовать reflection.
Например, через класс Activator.
Но использование reflection'а имеет некоторый (хотя и обычно терпимый) оверхед, плюс, оно просто не интересно =), поэтому можно попробовать иначе.
Воспользоваться так называемыми деревьями выражений, появившимися в .NET BCL 3.5. Они позволяют динамически строить и анализировать (как это делают провайдеры LINQ) AST выражений (в том числе, соответствующих делегатам). А потом выражения для делегатов можно откомпилировать в CIL (который затем JIT откомпилирует в native-код). 
Самое лучшее - когда типы, используемые в выражении известны. 
Тогда построения дерева выражения можно возложить на компилятор, написав что-то вроде:

Expression<Func<char[],string>> e = chars => new string(chars);

Но если бы типы были известны, вообще делать было бы нечего. Поэтому нам придется строить дерево вручную. Что, в общем-то, тоже несложно.
Легко увидеть, что дерево выражения для данного конструктора имеет вид (в псевдокоде)

(lambda (chars)(new (get-constructor (typeof string) (typeof chars[])) chars)

В реальном коде на C# это будет выглядеть как:

var p = Expression.Parameter(typeof(char[]), "chars");
var lambda = Expression.Lambda<Func<string>>(
    Expression.New(typeof(string).GetConstructor(typeof(char[]), p);

аналогично и для других конструкторов: 

new T(params) ->
(lambda (params) (new
  (get-constructor (typeof T) (map (lambda (p) (typeof p)) params)
  params)


и дерево будет выглядеть как
var parameters = (from t in argTypes
                  select Expression.Parameter(t, "@"+t))
                  .ToArray();
Expression.Lambda(
  Expression.New(targetType.GetConstructor(argTypes), parameters),
  parameters);


N.B.: ВАЖНО, чтобы параметры в теле лямбда-функции совпадали с ее параметрами, т.к. компилятор ищет их именно по совпадению, а не по имени.
Как видно, реальный код хотя и отличается, но не очень значительно.
Я наваял небольшой класс, кэширующий скомпилированные конструкторы. Замеры показали, что однократная компиляция+извлечение из словаря обгоняют чистый рефлекшен где-то с 16 тыс. созданий объектов, скэшированный же явным образом результат вообще вне конкуренции, т.к. это просто вызов конструктора.
В общем, expression trees могут оказаться хорошей заменой System.Reflection.Emit или System.CodeDom.Compiler там, где надо сгенерировать код на лету, но до порождения CIL или генерации кода в виде текста напрямую спускаться не хочется.
При этом, возможности expression trees ограничены - в них сложно обеспечить последовательное выполнение команд (разве что используя для этого AndAlso) и обработку исключений, нельзя породить класс (не для этого они созданы) и пр.
Опять же - не для того они были сделаны =)