СЕКРЕТЫ
МНОГОПОТОЧНОСТИ .NET
Елисеев Сергей
Санкт-Петербург, СКАУТ
2013
Agenda
Потоки Windows vs потоки CLR
Почему не потоки
Таски
Особенности TrheadPool
Предположения .NET о ваших тасках
Пример – 100 тасок.
PLINQ vs PARALLEL.FOR(EACH)
Cancelling.
Exception handling.
Потоки Windows и потоки CLR
Сейчас одно и то же. Но были попытки сделать
потоки CLR на нитях.
Почему не потоки?
Поток – тяжелый объект.
Затраты на переключение контекста.
Занимает много памяти по умолчанию. 1 мб
Для каждого потока необходимо писать свой
код обработки исключений.
Выход: пользоваться пулом потоков .NET
TASKS TASKS TASKS
Наша задача выражать работу в тасках.
Задача .net выполнять таски правильно.
Почему не ThreadPool?
Не предоставляет удобного способа
обработки исключений
По факту – устарел
НО: Task – это обертка над
ThreadPool, которая расходует
память.
Как правильно создавать TASK
• Task.Factory.StartNew();
• Vs
• new Task(…).Start()
Как правильно создавать TASK
• Task.Factory.StartNew(); - WINNER!!!
• Vs
• new Task(…).Start()
• - необходимы затраты на синхронизацию
• Причина необходимости – проверить, что START
вызывается только один раз.
Task Granularity?
Конфигурирование ThreadPool
• SETMAXTHREAD
• SETMINTHREAD
Предположение .net о ваших тасках.
• Таск маленький. 1-2 секунды
• Выполнение может идти в любом порядке.
Решение
Создать несколько Tasks.
Когда одна заканчивается
запускать новую.
Перегрузки Parralel.For/Foreach
public class ParallelOptions{
public ParallelOptions();
public CancellationToken CancellationToken { get; set; } //
Default=CancellationToken.None
public Int32 MaxDegreeOfParallelism { get; set; } // Default=-1 (# of available
CPUs)
public TaskScheduler TaskScheduler { get; set; } //
Default=TaskScheduler.Default
}
LINQ
• Where, Select, SelectMany, GroupBy, Join, OrderBy,
• Skip, Take – все это можно выполнить в нескольких
потоках.
AsParallel
var query =
from type in assembly.GetExportedTypes().AsParallel()
orderby type.FullName
let obsoleteAttrObj = (ObsoleteAttribute)
Attribute.GetCustomAttribute(method, obsoleteAttrType)
select …
// Display the results
foreach (var result in query) Console.WriteLine(result);
ForAll
// Display the results
query.ForAll(Console.WriteLine);
AsSequential
AsOrdered (AsUnordered)
Unordored Operations:
Distinct, Except, Intersect, Union, Join, GroupBy, GroupJoin, and ToLookup.
Ordored Operations: OrderBy, OrderByDescending, ThenBy,
and ThenByDescending.
Скорее всего, будет эффективнее выполнить последовательно Concat,
ElementAt(OrDefault), First(OrDefault), Last(OrDefault), Skip(While),
Take(While),
or Zip.
Методы расширения
WithCancellation(
CancellationTokencancellationToken)
WithDegreeOfParallelism (Int32degreeOfParallelism)
WithExecutionMode(ParallelExecutionModeexecutionMod
e)
И др.
Plinq vs Parallel.For(each)
• Если у нас простой независимый перебор по
элементам с выполнением операции то выбираем
Parralel.For
•
Plinq vs Parallel.For(each)
• Если необходимо сохранить порядок, то лучше
использовать Plinq
• var ProcessedMovie =
• Movie
• .AsParallel()
• .AsOrdered()
• .Select(frame => ConvertToGrayscale(frame));
Plinq vs Parallel.For(each)
Если обработка с выборкой – PLINQ
PLINQ
Plinq vs Parallel.For(each) Parralel.For
Plinq vs Parallel.For(each). Обаботка
двух коллекций.
PLINQ Winner
PLINQ
Plinq vs Parallel.For(each). Обаботка
двух коллекций.
PLINQ Winner
Parralel.For
Plinq vs Parallel.For(each). Поиск до
первого совпадения.
Parallel.For - WIN
Parralel.For
Timers
• Когда: Когда необходимо выполнять задачу
периодически.
• В таймере можно получать сообщение о том что таска
упала, и можно перезапускать ее.
Обработка исключений
C thread было все плохо
Обработка исключений
// Start a Task that throws a NullReferenceException:
Task task = Task.Run (() => { throw null; });
try
{
task.Wait();
}
catch (AggregateException aex)
{
if (aex.InnerException is ullReferenceException)
Console.WriteLine ("Null!");
else
throw;
}
Что, если создали Task, и
забыли.
Если она упала, то:
1) Когда она будет уничтожаться сборщиком мусора
поток финализатора пробросит исключение
Если мы ожидали таску с таймаутом, то все исключения которые
она бросила после истечения таймаута считаются непоймаными.
Если обратиться к полю Exception у таска,
то все непойманные исключения пометятся станут пойманными.
Cancelling
Cancelling
Спасибо за внимание!
Почему DEAD LOCK – 100%?

Presentation_1369080393540

Editor's Notes

  • #7 Если необходимо уменьшить потребление памяти приложением, то есть путь перехода к тред пулу.
  • #11 Окна решают на каком процессе им исполнится. Обычно . net создает 2 потока на каждое ядров пуле. У каждого потока есть свои очереди. Пул потоков действует по эвристическому алгоритму. Если приложение должно выполнить множество заданий и при этом имеются доступные процессоры, пул создает больше потоков. При снижении загрузки приложения потоки из пула самоуничтожаются.
  • #16 Рихтер предупреждает что так лучше не делать. Если поставить минимальное, то значит Thread Pool будет соз….
  • #20 Стартуем таски без каких либо опций. Она потихоньку начинает вбрасыввать навые таски Если пишем лонг ранинг опшн то получаем перегруженные таски. Не хорошая ситуация. Если мы стартуем с лонг ранинг опшн. Мы сразу получим 100 запущенных тасков.
  • #24 По факту парралел использует те же самые таски, но делает это внутри, тем самым облегчая нам жизнь.
  • #25 Если вы можете запустить и фор и форич то лучше запускать первый. Быстрее.
  • #26 // Allows cancellation of the operation public CancellationToken CancellationToken { get; set; } // // Allows you to specify the maximum number of work items // that can be operated on concurrently // Allows you to specify which TaskScheduler to use
  • #27 Можно сконвертить запрос в параллельный используя
  • #29 После вызова метода дальнейшие операции будут выполнятся в одном потоке. Обычно результаты в форич обрабатывает один поток, если мы хотим чтобы это делали многие, то лучше
  • #30 После вызова метода дальнейшие операции будут выполнятся в одном потоке. С такими методами скорее всего .net сам перейдет к выполнению последовательного кода. .net планирует выполнение запроса и может скатить его до последовательного. Но это можно предотвратить дав ему форс параллелизм. AsOrdered – бьет на группы и потом выполняет операции, а затем мержит. Теряем в производительности.
  • #31 После вызова метода дальнейшие операции будут выполнятся в одном потоке. Обычно результаты в форич обрабатывает один поток, если мы хотим чтобы это делали многие, то лучше
  • #32 1) Так как ForAll – это слишком дорого. Диспетчеризация более гибкая в parallel
  • #33 Пример с Plinq неэффективен либо по времени либо по памяти.
  • #34 Допустим нам надо обработать некоторые акции, а потом сделать выборку по обработки и что то сделать. . Обработка в потоке операций с данными. При правильном конфигурировании буфера можно добится хорошего результата. ParallelMergeOptions.NotBuffered: this specifies that each processed element is to be returned from each thread as soon as it’s produced. - Parallel.MergeOptions.AutoBuffered: this specifies that the elements be collected into a buffer, and the buffer’s contents are periodically yielded to the consuming thread all at once. - ParallelMergeOptions.FullyBuffered: this specifies buffering the entire output sequence, which might allow the results to be produced faster than using the other options, but may also take longer to yield the first element to the consuming thread.
  • #36 Минусы в том что надо заботится о сохранении порядка и о том, чтобы не выйти за пределы массива.
  • #38 В PLINQ тоже есть возможность останавливать очередь, но там она делается через cancellation tokensource , что не гарантирует немедленную остановку.
  • #41 Если мы вызовем Rusult у таски или wait то получим AggregatedException.
  • #42 Есл и вы н и разу не в ы з ы в а л и методы Wait и л и Result и не об ращались к свойству Exceptioп класса Task, код не «узнает» о появившихся исключениях. То есть вы не получ ите информации о том , что программа столкнулась с неожиданной проблемой . Для предотвращения подоб ной ситуации при попадан и объекта Task в сферу действия сборщика мусора метод Fiпalize объекта Task проверяет наличие исключений , и в случае их обнаружения вбрасывается исключение AggregateException. Вы не можете перехватить и с кл ю ч е н и е , вброшенное п отоком ф и н ализации сборщика мусора C L R , п оэтому процесс немедл е н н о завершается. Поэтому следует вн ести исп равления в код, вызвав оди н из помя нутых членов и гаранти ровав, что код «увидит» исключение и сможет после восстановиться . Для распознавания скрытых исключений можно зарегистрировать метод обратн о го в ы з о в а со стати ч е с к и м с о б ы т и е м U n observedTaskException класса TaskSc heduler. При попадан и и задания со скрытым исключением в сферу действия сборщика мусора это событие акти визи руется потоком ф и н ал изации сборщика мусора CLR . П осле этого об работч ику события передается объект Uno bservedTaskExceptionEventArg s, соде ржащи й скрытое и с к л ю ч е н и е Agg regateExceptio n . Чтобы предот вратить завершение процесса, имеет смысл вызвать метод SetObserved объекта UnobservedTas kExceptionEventArgs , информирующий об обработке исключения. Впрочем , не следует вводить это в стандартную практику. Как отмечено в главе 20, п роцесс луч ше завершить, чем позволить ему работать в поврежденном состоя н и и .
  • #43 Можем получить сведения, какая итерация выполнилась последней, на каком i свалились и т д.
  • #44 Так же есть метод ifCancellationrequested. В каких случаях применять тот или другой. Если наш таск что то возвращает то лучше использовать throw чтобы узнать завершилась операция или нет.
  • #45 Cancel кидает aggregate exception только если callback и , которые к нему подключены кидают эксепшн. А так то можно и не обрабатывать. Когда канселим необходимо перехватывать operationcancelledex, objectdisposed ex, aggreagted ex.