Все, что вы здесь делаете, неверно. Прекратите то, что вы делаете, и узнайте, как это работает, прежде чем писать больше асинхронного кода. Вы настраиваете себя на задачи, которые никогда не завершаются, потому что они никогда не запускались, и на задачи, которые никогда не завершаются, потому что они ожидаютсамих себя.Асинхронные рабочие процессы немного сложны.
Прежде всего: вы почти никогда не хотите использовать new Task
.Это просто означает «сделать задачу, которая представляет эту работу». Это не значит выполнять эту работу .new Task
составляет список дел;он не выполняет всю работу по списку!
Во-вторых, вы почти никогда не захотите использовать Task.Run
.Это означает создание задачи, представляющей работу , и назначение работника из пула для ее выполнения .Вы не хотите выделять работника, если только выполняемая вами работа не является синхронной и привязкой к процессору , которой ваша работа не является.
В-третьих, выпочти никогда не хотите использовать что-то, что уже является задачей .У вас в руках асинхронная лямбда. Возвращает задание при вызове, поэтому, если вы хотите задание для работающего рабочего процесса, вызывайте лямбду!
В-четвертых, вы почти никогда не захотите WaitAll
. Это разрушает весь смысл асинхронности, превращая асинхронный рабочий процесс обратно в синхронный рабочий процесс .
В-пятых, вы почти никогда не хотите вызывать Wait
для задачи по той же причине.Но это становится хуже!Вот список дел, который я хотел бы, чтобы вы сделали: во-первых, положите хлеб в тостер и начинайте его жарить.Во-вторых, синхронно ждать, пока бутерброд будет готово;не двигайтесь дальше, пока этот шаг не будет завершен.В-третьих, есть бутерброд.В-четвертых, когда тостер выскочит, выньте тост из тостера и положите на него немного ветчины, чтобы сделать бутерброд. Вы будете ждать вечно, если попытаетесь выполнить этот рабочий процесс .Асинхронные рабочие процессы тупик когда вы вставляете в них синхронные ожидания , потому что вы часто находитесь в ситуации, когда вы ожидаете работу, которую вы будете выполнять в будущем .
(Помимо этого последнего пункта: если вы находитесь в такой ситуации, правильное решение - НЕ , чтобы изменить второй шаг рабочего процесса на «нанять работника для завершения моего сэндвича и синхронно ждатьэтого работника нужно сделать ". Вы часто видите такого рода странное расточительное исправление неверного рабочего процесса. Когда вы удаляете синхронные ожидания и вставляете асинхронные ожидания (await
) в точках, где рабочий процесс не может продолжаться до тех пор, пока задача не будет завершена.завершив, вы обнаружите, что все ваши рабочие процессы могут выполняться одним потоком .)
Все, что вы делаете, является абсолютно неправильным способом асинхронного программирования, и вы не добьетесь успеха, есливы продолжаете делать это так .
ОК, теперь, когда вы знаете, как этого не делать,как вы это делаете?
- Если у вас есть метод или лямбда, который возвращает задачу, вызовите ее, чтобы получить задачу .
- Если вам нужнодождитесь завершения этой задачи, прежде чем продолжить ваш рабочий процесс,
await
задачу. - Если у вас есть несколько задач, и вам нужно выполнить их все, прежде чем ваш рабочий процесс можно будет продолжить, поместите их в коллекциюи затем вызовите
WhenAll
, чтобы получить новую задачу, которая представляет собой задачу завершения всех этих задач .Затем вы должны await
выполнить задачу .
Некоторые правильные рабочие процессы:
Вот самый простой из них:
private async Task GetStuffAsync()
{
// same work here
await MethodInsideThatNeedsAwaitingAsync();
// more work
}
private async Task DoItAsync()
{
// do work
await GetStuffAsync();
// do more work
}
Что еслиу вас есть несколько задач, и вы хотите ждать их всех, но они не должны ждать друг друга?
private async Task DoItAsync()
{
// do work
Task t1 = GetStuffAsync();
// do work
Task t2 = GetOtherStuffAsync();
// do more work
// We cannot continue until both are done
await t1;
await t2;
// do even more work
}
Что если у вас есть неизвестное число такихзадачи?
private async Task DoItAsync()
{
// do work
var tasks = new List<Task>();
while (whatever)
tasks.Add(GetStuffAsync());
// do work
// we cannot continue until all tasks are done
await Task.WhenAll(tasks);
// do more work
}