1
©LuxoftTraining2012
PostSharp Threading Pattern Library
Андрей Гордиенков
my@violet-tape.net
softblog.violet-tape.ru
2
Обо мне
 Фанат программирования и рассказов о программировании
 Ведет свой блог 5+ года: статьи и видео
 АОП евангелист
 Очень ленив, поэтому ищет пути как писать меньше, а делать больше
3
Немного из истории языков
 Ранние языки строилась вокруг модели памяти
 Оперирование переменными, а не адресами памяти
 FORTRAN I (1955)
 Дальнейшее развитие пошло вокруг модели исполнения
 Внедрение методов и подпрограмм
 FORTRAN II (1958)
 Внедрение областей видимости
 ALGOL 60
 Объединение концепций
 COBOL
 Скорее всего первый ООП язык был SIMULA
 C++, C# и Java прямые наследники SIMULA
4
Качества хорошей модели программирования
 Адекватные абстракции
 Проверяемость
 Локальность и разделение ответственности
 Детерминизм
 Производительность
5
Threading Pattern Library
 Предоставляет высокоуровневый механизм управления моделями
многопоточности для кода.
 Проверка времени компиляции и исполнения.
 Присутствует в PostSharp Express.
 Реализованные модели:
 Immutable
 Freezable
 Synchronized
 Reader/Writer Synchronized
 Actor
 Thread Affine
 Thread Unsafe
6
Необходимые условия работы моделей
 Для корректной работы может потребоваться использование специальных
коллекций
 AdvisableCollection<T>
 AdvisableDictionary<TKey,TValue>
 Поддержка концепции агрегации и композиции фреймворком.
 [Child]
 [Parent]
 [Reference]
7
Пример
[Aggregatable]
public class Invoice {
[Child]
public readonly AdvisableCollection<InvoiceLine> Lines = new AdvisableCollection<InvoiceLine>();
[Reference]
public Customer Customer;
}
[Aggregatable]
public class InvoiceLine {
[Reference]
public Product Product;
[Parent]
public Invoice ParentInvoice { get; private set; }
}
8
Ключевые идеи PostSharp TPL
 Основной фокус направлен на познавательные аспекты программирования
 Понятия Immutable, Actor, Freezable, Locking могут относиться к многопоточности
 Модели многопоточности относятся к классам, а не к приложению и модулям
 Разные модели многопоточности могут сосуществовать в одном приложении
 Шаблоны проектирования могут быть реализованы расширением языка, а не
кучей кода
 Можно точно определить, что есть валидный код на уровне классов. Исключая
инвариантность.
 Использование агрегации/композиции как основы для формализации шаблонов
9
Immutable
Суть: Объект не может быть изменен после того, как выполнилась вся цепочка
конструкторов.
 Подход в целом неадекватен для ООП.
 Инициализация объекта часто продолжается после создания объекта.
 Никак не регулируется изменяемость объектов принадлежащих классу.
 Фиксирование объекта происходит после выполнения последнего
конструктора в цепочке.
 Изменятся могут только поля/свойства помеченные [Reference]
10
Пример
[Immutable]
public class Invoice {
public long Id { get; set; }
public Invoice(long id) {
Id = id;
Items = new AdvisableCollection<Item>();
Items.Add(new Item("widget"));
}
[Child]
public AdvisableCollection<Item> Items { get; set; }
}
11
Freezable
Суть: Перед обработкой объекта в других потоках, его надо «заморозить».
Операция не обратимая.
 Рабочая модель для идеи «неизменяемых» объектов. В реализации
руководствовались следующим:
 Доступ к объекту запрещен для других потоков, пока объект не был заморожен. Даже на
чтение.
 После «заморозки» объект не может быть изменен ни при каких обстоятельствах.
 Метод Freeze() замораживает также все агрегируемые свойства
 «Дети» должны реализовывать модель Immutable или Freezable
12
Freezable
 Применение аспекта внедряет в класс интерфейс IFreezable
public interface IFreezable : IThreadAware {
void Freeze();
}
13
Пример
[Freezable]
public class Invoice {
[Child]
public readonly AdvisableCollection<InvoiceLine> Lines = new AdvisableCollection<InvoiceLine>();
[Reference]
public Customer Customer;
}
[Freezable]
public class InvoiceLine {
[Reference]
public Product Product;
[Parent]
public Invoice ParentInvoice { get; private set; }
}
14
Synchronized
Суть: Критические секции класса оборачиваются конструкцией lock(), которая
позволяет обрабатывать (читать/писать) себя только одному потоку
одновременно.
 «Классика жанра», самая популярная модель доступа к данным в
многопоточной среде.
 Главный подозреваемый при организации deadlock и задержке потоков.
 Падение производительности происходит при работе с долгими операциями вводавывода
 Реализация основана на классе Monitor
15
Пример
[Synchronized]
public class OrderService {
public void Process(int sequence) {
Console.WriteLine("sequence {0}", sequence);
Console.WriteLine("sleeping for 10s");
Thread.Sleep(new TimeSpan(0, 0, 10));
}
}
16
Reader-Writer Synchronized
Суть: Раздельные уровни блокировки частей кода для чтения и для записи. В
один момент времени чтение позволено многим потокам, запись – только
одному.
 Public и Internal методы класса должны быть помечены атрибутами:
 [Reader]
 [Writer]
 [UpgradableReader]
 Get/Set автоматически помечаются как [Reader]/[Writer]
 Реализация основана на ReaderWriterLockSlim классе
17
Пример
[ReaderWriterSynchronized]
public class Order {
public decimal Amount { get; set; }
public decimal Discount { get; set; }
[Child]
public AdvisableCollection<Item> lines = new AdvisableCollection<Item>();
public decimal AmountAfterDiscount {
get { return Amount - Discount; }
}
[Writer]
public void Set(decimal amount, decimal discount) {
if (amount < discount) {
throw new InvalidOperationException();
}
Amount = amount;
Discount = discount;
}
}
18
Actor
Суть: Запросы класса асинхронно перенаправляются в одну очередь исполнения
в которой выполняются по порядку в один поток.
 Любой public/internal метод упаковывается в сообщение, которое кладется в
очередь
 Класс реализует интерфейс IActor
 Реализация основана на классе ConcurrentQueue
 Шаблон требует, чтобы все методы относились к следующим категориям:
 Ничего не возвращали в результате работы
 Были асинхронными. Помечены словом async
public interface IActor : IThreadAware
{
IActorDispatcher Dispatcher { get; }
}
19
Пример
[Actor]
public class AverageCalculator {
private float sum;
private int count;
public void AddSample(float n) {
count++;
sum += n;
}
[Reentrant]
public async Task<float> GetAverage() {
return sum / count;
}
}
20
Thread Affine
Суть: Методы класса выполняется только в том потоке, в котором был создан
класс.
 Реализация просто запоминает поток создания объекта.
 Никаких особенностей =)
21
Пример
[ThreadAffine]
public class OrderService {
public void Process(int sequence) {
Console.WriteLine("sequence {0}", sequence);
Console.WriteLine("sleeping for 10s");
Thread.Sleep(new TimeSpan(0, 0, 10));
}
}
22
Thread Unsafe
Суть: При одновременном доступе к классу с нескольких потоков, выбрасывается
исключение.
 Не рекомендуется к использованию.
 Существует только для диагностики проблем многопоточности.
 Вызывает исключение, если смена значения происходит в другом потоке.
 Реализовано с помощью операции CompareExchange
23
Пример
[ThreadUnsafe]
internal class AverageCalculator {
private float sum;
private int count;
public void AddSample(float n) {
count++;
sum += n;
}
public float GetAverage() {
return sum / count;
}
}
24
Особенности использования
 Синхронные методы возвращающие результат должны быть помечены
атрибутом [ExplicitlySynchronized]
 Для таких методов/свойств просто не будет производится проверка
 Если точка входа в класс – приватный метод, то его надо обозначить
атрибутом [EntryPoint]
 Например, через делегат к приватному методу.
25
Ограничения при использовании
 Ограниченная проверка на этапе сборки
 PostSharp проверяет структурную композицию, а не поведение элементов
 Блокирующее ожидание в async методах
 Все async методы должны быть помечены атрибутом [Reentrant]
 Нет асинхронного ожидания
 Нет защиты хоста
 Не проводились тесты на наличие исключений OutOfMemoryException или
ThreadAbortException в процессе работы.
26
Написание своей валидации
 Фактически любой базовый аспект позволяет переопределить самостоятельно
метод CompileTimeValidate() для валидации на этапе компиляции
[Serializable]
public class MethodAttribute : OnMethodBoundaryAspect {
public override bool CompileTimeValidate(MethodBase method) {
}
}
[Serializable]
public class TypeAspect : TypeLevelAspect {
public override bool CompileTimeValidate(Type type) {
}
}
27
Вопросы
28
Ссылки
 Github https://github.com/VioletTape/PS_TPL_Examples
 PostSharp http://www.postsharp.net
29
©LuxoftTraining2012
Спасибо!
my@violet-tape.net
softblog.violet-tape.ru

PostSharp - Threading Model Library

  • 1.
    1 ©LuxoftTraining2012 PostSharp Threading PatternLibrary Андрей Гордиенков my@violet-tape.net softblog.violet-tape.ru
  • 2.
    2 Обо мне  Фанатпрограммирования и рассказов о программировании  Ведет свой блог 5+ года: статьи и видео  АОП евангелист  Очень ленив, поэтому ищет пути как писать меньше, а делать больше
  • 3.
    3 Немного из историиязыков  Ранние языки строилась вокруг модели памяти  Оперирование переменными, а не адресами памяти  FORTRAN I (1955)  Дальнейшее развитие пошло вокруг модели исполнения  Внедрение методов и подпрограмм  FORTRAN II (1958)  Внедрение областей видимости  ALGOL 60  Объединение концепций  COBOL  Скорее всего первый ООП язык был SIMULA  C++, C# и Java прямые наследники SIMULA
  • 4.
    4 Качества хорошей моделипрограммирования  Адекватные абстракции  Проверяемость  Локальность и разделение ответственности  Детерминизм  Производительность
  • 5.
    5 Threading Pattern Library Предоставляет высокоуровневый механизм управления моделями многопоточности для кода.  Проверка времени компиляции и исполнения.  Присутствует в PostSharp Express.  Реализованные модели:  Immutable  Freezable  Synchronized  Reader/Writer Synchronized  Actor  Thread Affine  Thread Unsafe
  • 6.
    6 Необходимые условия работымоделей  Для корректной работы может потребоваться использование специальных коллекций  AdvisableCollection<T>  AdvisableDictionary<TKey,TValue>  Поддержка концепции агрегации и композиции фреймворком.  [Child]  [Parent]  [Reference]
  • 7.
    7 Пример [Aggregatable] public class Invoice{ [Child] public readonly AdvisableCollection<InvoiceLine> Lines = new AdvisableCollection<InvoiceLine>(); [Reference] public Customer Customer; } [Aggregatable] public class InvoiceLine { [Reference] public Product Product; [Parent] public Invoice ParentInvoice { get; private set; } }
  • 8.
    8 Ключевые идеи PostSharpTPL  Основной фокус направлен на познавательные аспекты программирования  Понятия Immutable, Actor, Freezable, Locking могут относиться к многопоточности  Модели многопоточности относятся к классам, а не к приложению и модулям  Разные модели многопоточности могут сосуществовать в одном приложении  Шаблоны проектирования могут быть реализованы расширением языка, а не кучей кода  Можно точно определить, что есть валидный код на уровне классов. Исключая инвариантность.  Использование агрегации/композиции как основы для формализации шаблонов
  • 9.
    9 Immutable Суть: Объект неможет быть изменен после того, как выполнилась вся цепочка конструкторов.  Подход в целом неадекватен для ООП.  Инициализация объекта часто продолжается после создания объекта.  Никак не регулируется изменяемость объектов принадлежащих классу.  Фиксирование объекта происходит после выполнения последнего конструктора в цепочке.  Изменятся могут только поля/свойства помеченные [Reference]
  • 10.
    10 Пример [Immutable] public class Invoice{ public long Id { get; set; } public Invoice(long id) { Id = id; Items = new AdvisableCollection<Item>(); Items.Add(new Item("widget")); } [Child] public AdvisableCollection<Item> Items { get; set; } }
  • 11.
    11 Freezable Суть: Перед обработкойобъекта в других потоках, его надо «заморозить». Операция не обратимая.  Рабочая модель для идеи «неизменяемых» объектов. В реализации руководствовались следующим:  Доступ к объекту запрещен для других потоков, пока объект не был заморожен. Даже на чтение.  После «заморозки» объект не может быть изменен ни при каких обстоятельствах.  Метод Freeze() замораживает также все агрегируемые свойства  «Дети» должны реализовывать модель Immutable или Freezable
  • 12.
    12 Freezable  Применение аспектавнедряет в класс интерфейс IFreezable public interface IFreezable : IThreadAware { void Freeze(); }
  • 13.
    13 Пример [Freezable] public class Invoice{ [Child] public readonly AdvisableCollection<InvoiceLine> Lines = new AdvisableCollection<InvoiceLine>(); [Reference] public Customer Customer; } [Freezable] public class InvoiceLine { [Reference] public Product Product; [Parent] public Invoice ParentInvoice { get; private set; } }
  • 14.
    14 Synchronized Суть: Критические секциикласса оборачиваются конструкцией lock(), которая позволяет обрабатывать (читать/писать) себя только одному потоку одновременно.  «Классика жанра», самая популярная модель доступа к данным в многопоточной среде.  Главный подозреваемый при организации deadlock и задержке потоков.  Падение производительности происходит при работе с долгими операциями вводавывода  Реализация основана на классе Monitor
  • 15.
    15 Пример [Synchronized] public class OrderService{ public void Process(int sequence) { Console.WriteLine("sequence {0}", sequence); Console.WriteLine("sleeping for 10s"); Thread.Sleep(new TimeSpan(0, 0, 10)); } }
  • 16.
    16 Reader-Writer Synchronized Суть: Раздельныеуровни блокировки частей кода для чтения и для записи. В один момент времени чтение позволено многим потокам, запись – только одному.  Public и Internal методы класса должны быть помечены атрибутами:  [Reader]  [Writer]  [UpgradableReader]  Get/Set автоматически помечаются как [Reader]/[Writer]  Реализация основана на ReaderWriterLockSlim классе
  • 17.
    17 Пример [ReaderWriterSynchronized] public class Order{ public decimal Amount { get; set; } public decimal Discount { get; set; } [Child] public AdvisableCollection<Item> lines = new AdvisableCollection<Item>(); public decimal AmountAfterDiscount { get { return Amount - Discount; } } [Writer] public void Set(decimal amount, decimal discount) { if (amount < discount) { throw new InvalidOperationException(); } Amount = amount; Discount = discount; } }
  • 18.
    18 Actor Суть: Запросы классаасинхронно перенаправляются в одну очередь исполнения в которой выполняются по порядку в один поток.  Любой public/internal метод упаковывается в сообщение, которое кладется в очередь  Класс реализует интерфейс IActor  Реализация основана на классе ConcurrentQueue  Шаблон требует, чтобы все методы относились к следующим категориям:  Ничего не возвращали в результате работы  Были асинхронными. Помечены словом async public interface IActor : IThreadAware { IActorDispatcher Dispatcher { get; } }
  • 19.
    19 Пример [Actor] public class AverageCalculator{ private float sum; private int count; public void AddSample(float n) { count++; sum += n; } [Reentrant] public async Task<float> GetAverage() { return sum / count; } }
  • 20.
    20 Thread Affine Суть: Методыкласса выполняется только в том потоке, в котором был создан класс.  Реализация просто запоминает поток создания объекта.  Никаких особенностей =)
  • 21.
    21 Пример [ThreadAffine] public class OrderService{ public void Process(int sequence) { Console.WriteLine("sequence {0}", sequence); Console.WriteLine("sleeping for 10s"); Thread.Sleep(new TimeSpan(0, 0, 10)); } }
  • 22.
    22 Thread Unsafe Суть: Приодновременном доступе к классу с нескольких потоков, выбрасывается исключение.  Не рекомендуется к использованию.  Существует только для диагностики проблем многопоточности.  Вызывает исключение, если смена значения происходит в другом потоке.  Реализовано с помощью операции CompareExchange
  • 23.
    23 Пример [ThreadUnsafe] internal class AverageCalculator{ private float sum; private int count; public void AddSample(float n) { count++; sum += n; } public float GetAverage() { return sum / count; } }
  • 24.
    24 Особенности использования  Синхронныеметоды возвращающие результат должны быть помечены атрибутом [ExplicitlySynchronized]  Для таких методов/свойств просто не будет производится проверка  Если точка входа в класс – приватный метод, то его надо обозначить атрибутом [EntryPoint]  Например, через делегат к приватному методу.
  • 25.
    25 Ограничения при использовании Ограниченная проверка на этапе сборки  PostSharp проверяет структурную композицию, а не поведение элементов  Блокирующее ожидание в async методах  Все async методы должны быть помечены атрибутом [Reentrant]  Нет асинхронного ожидания  Нет защиты хоста  Не проводились тесты на наличие исключений OutOfMemoryException или ThreadAbortException в процессе работы.
  • 26.
    26 Написание своей валидации Фактически любой базовый аспект позволяет переопределить самостоятельно метод CompileTimeValidate() для валидации на этапе компиляции [Serializable] public class MethodAttribute : OnMethodBoundaryAspect { public override bool CompileTimeValidate(MethodBase method) { } } [Serializable] public class TypeAspect : TypeLevelAspect { public override bool CompileTimeValidate(Type type) { } }
  • 27.
  • 28.
  • 29.