Ответ 1
Итак, второй - простой, поэтому отпустите его.
Для второй задачи t2
вы ничего не делаете с результатом Task.Delay(1000)
. Вы не await
его, вы не Wait
и т.д. Учитывая, что метод не является async
, я предполагал, что вы предназначались для него как блокирующее ожидание. Чтобы сделать это, вы хотите добавить Wait()
в конец вызова Delay
, чтобы сделать его ожидающим блокировки, или просто используйте Thread.Sleep()
.
Для первой задачи вас укусит тот факт, что вы используете var
. Ясно, что происходит, когда вы не используете var
:
Task<Task<int>> t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
Вы возвращаете задачу задачи int
, а не только Task
из int
. Внешняя задача "завершена", как только заканчивается внутренняя задача. Когда вы используете WhenAll
, вам все равно, когда закончится внешняя задача, вы заботитесь о завершении внутренней задачи. Существует несколько способов справиться с этим. Один из них - использовать Unwrap
.
Task<int> t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
}).Unwrap();
Теперь вы ожидаете, что ожидаемые Task<int>
и WhenAll
займут не менее 2000 миллисекунд, как и ожидалось. Вы также можете добавить другой вызов await
, чтобы сделать то же самое:
Task<int> t1 = await Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
Как упоминалось svick в комментарии, другим вариантом было бы просто использовать Task.Run
вместо StartNew
. Task.Run
имеет специальный набор перегрузок для методов, которые принимают Func<Task<T>>
и возвращают a Task<T>
и автоматически разворачивают их для вас:
Task<int> t1 = Task.Run(async () =>
{
await Task.Delay(2000);
return 2;
});
По этой причине предпочтительнее использовать Task.Run
как параметр по умолчанию при создании async lambdas, поскольку он "обрабатывает" эту проблему для вас, хотя лучше всего знать об этом для сложных случаев, когда вы можете 't использовать Task.Run
.
Наконец, мы переходим к тому варианту, который вы не делали, и это то, что вы, вероятно, должны делать в этом случае. Поскольку Task.Delay
уже возвращает задачу, нет необходимости вставлять ее в StartNew
. Вместо создания вложенной задачи и использования Unwrap
вы можете просто не обернуть ее в первую очередь:
var t3 = Task.Delay(3000);
await Task.WhenAll(t1, t2, t3);
Если вы просто хотите дождаться фиксированного количества времени, что вы должны делать.