3. HYS Enterprise is a Dutch software
development company with more than
200 talented engineers from all over
the world hys-enterprise.com
UkraineNetherlands
8. Конкурентность
Полезность:
- В любой ситуации, когда приложение должно делать что-то одно во
время работы над чем-то другим.
- Для конечного пользователя, чтобы реагировать на ввод данных
пользователем во время записи в базу данных.
- Серверные приложения используют конкурентность для реакции на
второй запрос в ходе завершения первого запроса.
.NET Meetup
19. Вертикальная масштабируемость
Улучшение качеств текущих серверов:
- Больше RAM
- Быстрые HDD
- Больше CPU Cores
- Более оптимальное использование ресурсов
- Оптимальное использование потоков
- Освобождение потока как можно скорее
.NET Meetup
24. Async
● Добавляется в объявление метода.
● Разрешает использование ключевого слова await внутри этого метода.
● Дает инструкцию компилятору сгенерировать для этого метода
конечный автомат
.NET Meetup
25. Await
● Выполняет асинхронное ожидание по своему аргументу. Сначала
проверяет, завершилась ли операция: если да, то метод продолжает
выполняться синхронно.
● В противном случае await приостанавливает async-метод и возвращает
незавершенную задачу.
● Когда операция завершится позднее, метод async продолжает
выполнение.
.NET Meetup
27. Async-метод
Первая синхронная часть выполняется в потоке, который вызвал метод.
Все синхронные части пытаются возобновить продолжение в исходном
контексте.
Если вызвать метод DoSomethingAsync из UI-потока, каждая из его
синхронных частей будет выполняться в этом UI-потоке, но если вызвать
его из потока из пула потоков, то каждая из синхронных частей будет
выполняться в любом потоке из пула потоков.
.NET Meetup
31. Взаимоблокировка: Решение
.NET Meetup
void Deadlock()
{
Task task = WaitAsync();
// Синхронное блокирование с
ожиданием завершения async метода.
task.Wait();
}
async Task WaitAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1))
.ConfigureAwait(false);
}
32. Взаимоблокировка: Лучшее
.NET Meetup
async void Deadlock()
{
Task task = await WaitAsync();
}
async Task WaitAsync()
{
// await сохранит текущий контекст
await Task.Delay(TimeSpan.FromSeconds(1));
// попытается возобновить метод в этой точке с
этим контекстом.
}
33. Синхронизация контекста
Хорошей практикой считается вызывать ConfigureAwait в базовых
“библиотечных” методах и возобновлять контекст только тогда, когда
потребуется - в ваших внешних методах “пользовательского интерфейса”.
.NET Meetup
34. Синхронизация контекста
ConfigureAwait(false) конфигурирует Task так, что возвращение из await не
обязательно должно выполняться в вызывающем контексте.
Использовалось для избегания Deadlocks.
И для того, чтобы не ожидать вызывающий контекст.
.NET Meetup
35. Синхронизация контекста
ASP.NET Core не имеет синхронизации контекста
- Используется Thread pool
- Улучшает производительность
- Легче писать async code. Не ответственность разработчика
- Task.Result больше не приводит к Deadlock,
но приводит к блокировке вызывающего потока
.NET Meetup
57. async void
● Только для event handlers
● Тяжело обрабатывать ошибки
● Сложно тестировать
● Нелегко оповещать вызывающий код о статусе своего выполнения
.NET Meetup
58. ValueTask
● Cокращает затраты памяти, если результат в основном является
синхронным.
● Например, если результат может быть прочитан из кэша в памяти.
.NET Meetup
60. ValueTask: недостатки
● ValueTask или ValueTask<T> может ожидаться только один раз
● Можно вызвать AsTask только один раз.
● Синхронная загрузка результата из Task<T> блокирует вызывающий
поток до завершения задачи; ValueTask<T> таких гарантий не дает.
● Синхронное получение результатов от ValueTask или ValueTask<T>
● может быть выполнено только один раз, после завершения ValueTask.
.NET Meetup
74. Синхронизация
Если в вашем приложении используется конкурентность,
следует остерегаться ситуаций, в которых один блок
кода должен обновлять данные, пока другой код
обращается к тем же данным. Столкнувшись с подобной
ситуацией, необходимо синхронизировать доступ к
данным
.NET Meetup
76. Синхронизация для защиты
Необходима при выполнении всех трех условий:
1. Несколько частей кода выполняются одновременно
2. Общие данные
3. Обновление данных
.NET Meetup
77. Синхронизация для защиты
Цель защиты данных заключается в том, чтобы каждая
часть кода имела целостное представление данных.
Если одна часть кода обновляет данные, вы можете
воспользоваться синхронизацией, чтобы обновления
воспринимались как атомарные для остальных
компонентов системы.
.NET Meetup
78. Нужна синхронизации для value?
.NET Meetup
async Task<int> MyMethodAsync()
{
int value = 10;
await Task.Delay(TimeSpan.FromSeconds(1));
value += 1;
await Task.Delay(TimeSpan.FromSeconds(1));
value += 1;
await Task.Delay(TimeSpan.FromSeconds(1));
return await Task.FromResult(value);
}
79. Нужна синхронизации для value?
.NET Meetup
async Task<int> MyMethodAsync()
{
int value = 10;
await Task.Delay(TimeSpan.FromSeconds(1));
value += 1;
await Task.Delay(TimeSpan.FromSeconds(1));
value += 1;
await Task.Delay(TimeSpan.FromSeconds(1));
return await Task.FromResult(value);
}
Нет
80. Нужна синхронизации для value?
.NET Meetup
private int value;
async Task ModifyValueAsync()
{
var originalValue = value;
await Task.Delay(TimeSpan.FromSeconds(1));
value = originalValue + 1;
}
81. Нужна синхронизации для value?
.NET Meetup
private int value;
async Task ModifyValueAsync()
{
var originalValue = value;
await Task.Delay(TimeSpan.FromSeconds(1));
value = originalValue + 1;
}
Да
82. Lock блокировка
.NET Meetup
private readonly object _mutex = new object();
private int _value;
public void Increment()
{
lock (_mutex)
{
_value = _value + 1;
}
}
83. Lock блокировка
.NET Meetup
● Ограничьте видимость блокировки:
private объект, не string, не this
● Защищать только то, что должно быть защищено
● Минимальный объем кода, защищенного блокировкой:
минимум блокирующих вызовов в lock
● Никакого произвольного кода при удержании блокировки:
не инициируйте события, не вызывайте делегаты и другие методы
85. .NET Meetup
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
private int _value;
public async Task DelayAndIncrementAsync()
{
await _mutex.WaitAsync();
try
{
int oldValue = _value;
await Task.Delay(TimeSpan.FromSeconds(oldValue));
_value = oldValue + 1;
}
finally
{
_mutex.Release();
}
}
86. Синхронизация передачи данных
Синхронизация при передаче данных используется в тех
случаях, когда один блок кода должен оповестить другой
блок кода о некотором условии (например, о
поступлении нового сообщения)
.NET Meetup
87. Блокировка через сигналы
.NET Meetup
private readonly ManualResetEventSlim _initialized = new ManualResetEventSlim();
private int _value;
public int ReturnResultFromThreadA()
{
_initialized.Wait();
return _value;
}
public void InitializeFromThreadB()
{
_value = 13;
_initialized.Set();
}
88. Async блокировка через сигналы
.NET Meetup
private readonly TaskCompletionSource<object> _initialized = new TaskCompletionSource<object>();
private int _value;
public async Task<int> WaitForInitializationAsync()
{
await _initialized.Task;
return _value1 + 1;
}
public void Initialize()
{
_value = 5;
_initialized.TrySetResult(null);
}
93. async Task<MultipartFormDataStreamProvider> Read(HttpContent content)
{
var multipartContentProvider = new MultipartFormDataStreamProvider(_tmpFolderPath);
var task = content.ReadAsMultipartAsync(multipartContentProvider);
if (task.IsFaulted || task.IsCanceled)
throw new ContentFormatException($"HTTP message is not in correct format");
return await task;
}
Исключения: Bad Code
.NET Meetup
94. .NET Meetup
async Task TestAsync()
{
Task task = ThrowExceptionAsync(); // Исключение выдается методом и помещается в задачу
try
{
await task; // Здесь исключение будет выдано повторно
}
catch (Exception)
{
// Здесь исключение правильно перехватывается.
}
}
Исключения: Good Code
106. .NET Meetup
async Task IssueCancelRequestAsync()
{
using var cts = new CancellationTokenSource();
var task = CancelableMethodAsync(cts.Token);
...
cts.Cancel();
try
{
await task; // операция выполнилась успешно до запроса на завершение
}
catch (OperationCanceledException)
{
// операция была отменена
}
catch (Exception)
{
// операция завершилась с другой ошибкой до отмены
}
}
107. Ожидание отмены
.NET Meetup
public void CancelableMethod(CancellationToken cancellationToken)
{
for (int i = 0; i < 100000; i++)
{
// some work here
Thread.Sleep(1);
if (i % 1000 == 0)
cancellationToken.ThrowIfCancellationRequested();
}
}
108. Отмена по таймауту
● Конкурентный поток с фиксированным временем
выполнения
● CancellationToken
.NET Meetup
113. Прогресс
Используем IProgress<T> и Progress<T>.
Async-метод получает аргумент IProgress<T>;
T - тип прогресса, о котором хотим сообщать.
.NET Meetup