На данный вопрос уже ответили:
Здравствуйте, извиняюсь за вопрос по этой теме т.к существует довольно огромное количество статей об этих ключевых словах, но возможно такое количество статей и ввело меня в некое не до понимание.
Я просто хочу узнать правильно ли я все понял и задать походу пару вопросов.
В итого что это дает в приложениях
Вопросы
Для начала, ваши предположения.
Ну как бы технически говоря да. Но есть ещё одна важная для понимания вещь: с ключевым словом async функция разбиваются на куски так, что между этими кусками функция вообще нигде не бежит. А каждый из кусков выполняется синхронно, как обыкновенная функция. Границы этих кусков идут по await.
«Await ставится перед операцией которая выполняется во вторичном потоке.» — это неверно, await означает лишь, что в этой точке функция прекращает выполнение, и возобновляется тогда, когда Task, по отношению к которому производится await, завершается.
Task, как мы уже видели, вовсе не означает «кусок кода, бегущий в каком-то потоке». Например, async-функция производит Task, который бежит в конкретном потоке лишь иногда, кусками.
Теперь, ваши вопросы.
В общем и целом правда, но не на одну часть, а на много. Представьте себе, например, такой код:
async Task PrintSlowly(IEnumerable<int> data)
{
Console.WriteLine("begin");
foreach (var n in data)
{
await Task.Delay(1000);
Console.WriteLine(data);
}
Console.WriteLine("end");
}
В этом методе у нас k + 1 кусок, где k — количество элементов, полученных из IEnumerable<int>.
Если await выполняется в UI-потоке (или в любом потоке, в котором есть свой TaskScheduler/SynchronizationContext), то следующий кусок функции перебрасывается для выполнения в тот же поток/SynchronizationContext. Если же вам это не нужно, вы можете сказать ConfigureAwait(false), что означает «мне безразлично, в каком контексте выполнятся остальные куски async-функции». При этом рантайм может заставить их выполняться где угодно, гарантий нет.
Нет, операция, на которую делается await, не обязательно будет выполняться в другом потоке. Task не есть «кусок кода, который выполняется где-то ещё». Если эта операция реально не блокирует текущий поток, то да, текущий поток будет свободен. Но вы легко можете написать Task, который будет блокировать текущий поток:
async Task Weird()
{
if (Math.Sin(0) == 42)
await Task.Delay(1000);
for (int x = 0; x < 1_000_000; x++)
for (int y = 0; y < 1_000_000; y++)
for (int z = 0; z < 1_000_000; z++)
{
if (x * x * x * x + y * y * y * y == z * z * z * z)
throw new Exception("Ферма лох");
}
}
Где и как выполняется Task, определяется исключительно самим Task'ом. Единственный случай, когда Task целиком выполняется на побочном потоке, есть Task, запущенный через Task.Run() (в этом случае поток берётся из пула потоков). В остальных случаях забота о том, где именно выполняться, лежит на самом Task'e, async/await этим не занимается, и даже не требует, чтобы Task вообще где-то выполнялся. Task должен бы завершаться, это да (и то не обязан), а выполняться он может вообще нигде. Вот пример:
static Task WaitTimer()
{
var tcs = new TaskCompletionSource<int>();
new System.Threading.Timer(o => tcs.SetResult(0), null, 3000,
System.Threading.Timeout.Infinite);
return tcs.Task;
}
И да, обязательно почитайте ответы к этому вопросу.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости