PostSharp - Threading Model Library

Post on 18-Jul-2015

3.687 views 2 download

Transcript of PostSharp - Threading Model Library

1

© L

uxo

ft T

rain

ing

20

12

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

© L

uxo

ft T

rain

ing

20

12

Спасибо!

my@violet-tape.net

softblog.violet-tape.ru