Асинхронность. Async Await - Некоторые моменты 

Page / - Изменено Alexandr Fokin в 2024/01/09 19:24 

Некоторые моменты 
Изменено Alexandr Fokin
в 2024/01/09 19:24

Оглавление

Исключения | Exception 	async Task ActionAsync	Если внутри метода возникнет исключение, то будет возвращен Task с исключением	
Task ActionAsync	Если внутри метода возникнет исключение, то оно будет проброшено наверх напрямую.
Если мы хотим сохранить общее поведение, то необходимо использовать конструкцию:
try
{
   return Task.CompletedTask;
}
catch (Exception ex)
{
   return Task.FromException(ex);
}	
	
AsyncLocal	async Task ActionAsync	В случае, если внутри метода будет задано значение AsyncLocal контейнера, то при выходе из метода оно будет сброшено на родительское значение.	
Task ActionAsync	В случае, если внутри метода будет задано значение AsyncLocal контейнера, то при выходе из метода оно не будет сброшено.	
	
Выполнение кода	1)	var tasks = Enumerable
    .Range(0, 10)
    .Select(
       async e => {
            action1();
           await Task.Delay(TimeSpan.FromSeconds(10));
            action2();
        }
    )
    .ToArray();
await Task.WhenAll(tasks);	action1 будут выполнены одним потоком (который вызвал Enumarable) последовательно друг за другом (без какого-либо параллелизма). После этого происходит асинхронное ожидание и прерывание потока исполнения.
action2 будет выполнено после ожидания при этом поток его выполнения зависит от параметров SynchronizationContext | Контекст синхронизации окружения (при этом могут исполняться параллельно друг другу в разных потоках.

Такой подход подходит для ситуации, когда мы не стремимся параллелить action1 (он не является ресурсоемким).	
2)	var tasks = Enumerable
    .Range(0, 10)
    .Select(
        e => Task.Run(
           async () => {
                action1();
               await Task.Delay(TimeSpan.FromSeconds(10));
                action2();
            }
            )
    )
    .ToArray();
await Task.WhenAll(tasks);	При таком вызове  на каждый отдельный элемент будет запущена отдельная задача через планировщик. Действия будут выполняться параллельно друг другу (в том числе и action1) в разных потоках. Будет запланировано 10 задач.
По умолчанию код, внутри делегата Task.Run (или Parallel.ForEachAsync) будет выполнен без контекста синхронизации, таким образом action2 будет запланирован к исполнению на потоке их пула.

Такой подход не очень хорош, если каждая операция не является ресурсоемкой с точки зрения процессора.	
3) 	await Parallel.ForEachAsync(
    Enumerable.Range(0, 10),
   async (e, t) => 
    {
        action1();
       await Task.Delay(TimeSpan.FromSeconds(10));
        action2();
    }
    );	Данный метод позволяет выполнять действия параллельно, но при этом будет более экономичным чем 2 вариант т.к.