Поэтому мне недавно сказали, что то, как я использую .ContinueWith для задач, было неправильным способом их использования. Мне еще предстоит найти доказательства этого в Интернете, поэтому я спрошу вас, ребята, и посмотрю, какой будет ответ. Вот пример того, как я использую .ContinueWith:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}
Теперь я знаю, что это простой пример, и он будет работать очень быстро, но предположим, что каждая задача выполняет более длительную операцию. Итак, мне сказали, что в .ContinueWith вам нужно сказать prevTask.Wait (); в противном случае вы могли бы выполнить работу до завершения предыдущей задачи. Это вообще возможно? Я предполагал, что моя вторая и третья задачи будут выполняться только после завершения их предыдущей задачи.
Что мне сказали, как писать код:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 3");
});
}
источник
Ответы:
Эххх .... Я думаю, что в некоторых из текущих ответов чего-то не хватает: что происходит с исключениями?
Единственная причина, по которой вы вызываете
Wait
продолжение, - это наблюдение за потенциальным исключением из антецедента в самом продолжении. То же самое произойдет, если вы получили доступResult
в случае,Task<T>
а также если вы вручную получили доступ кException
свойству. Честно говоря, я бы не стал звонитьWait
или обращаться к вам,Result
потому что в случае исключения вы заплатите цену за повторное повышение, что не является ненужными накладными расходами. Вместо этого вы можете просто проверитьIsFaulted
собственность на антецедентеTask
. В качестве альтернативы вы можете создавать разветвленные рабочие процессы, связывая в цепочку несколько одноуровневых продолжений, которые срабатывают только в случае успеха или неудачи с помощьюTaskContinuationOptions.OnlyOnRanToCompletion
иTaskContinuationOptions.OnlyOnFaulted
.Теперь нет необходимости наблюдать исключение предшествующего события в продолжении, но вы можете не захотеть, чтобы ваш рабочий процесс продвигался вперед, если, скажем, «Шаг 1» не удался. В этом случае: указание
TaskContinuationOptions.NotOnFaulted
на вашиContinueWith
вызовы предотвратит запуск логики продолжения.Имейте в виду, что если ваши собственные продолжения не наблюдают за исключением, человек, ожидающий завершения этого рабочего процесса в целом, будет наблюдать за ним. Либо они находятся
Wait
вTask
восходящем потоке, либо добавили собственное продолжение, чтобы знать, когда оно будет завершено. Если это последнее, то при их продолжении необходимо использовать вышеупомянутую логику наблюдения.источник
TaskContinuationOptions
Вы правильно его используете.
Источник: метод Task.ContinueWith (действие как MSDN)
Необходимость вызывать
prevTask.Wait()
при каждомTask.ContinueWith
вызове кажется странным способом повторить ненужную логику - то есть делать что-то, чтобы быть «супер-уверенным», потому что вы на самом деле не понимаете, что делает определенный фрагмент кода. Как проверка на нуль, просто чтобы бросить туда,ArgumentNullException
где он все равно был бы брошен.Итак, нет, тот, кто сказал вам это, неправ и, вероятно, не понимает, почему
Task.ContinueWith
существует.источник
Кто тебе это сказал?
Цитата из MSDN :
Кроме того, какова была бы цель « Продолжить с», если бы он не ждал завершения предыдущей задачи?
Вы даже можете проверить это самостоятельно:
Task.Factory.StartNew(() => { Console.WriteLine("Step 1"); Thread.Sleep(2000); }) .ContinueWith((prevTask) => { Console.WriteLine("I waited step 1 to be completed!"); }) .ContinueWith((prevTask) => { Console.WriteLine("Step 3"); });
источник
Из MSDN на
Task.Continuewith
Я думаю, что то, как вы ожидаете, что это будет работать в первом примере, является правильным.
источник
Вы также можете рассмотреть возможность использования Task.Run вместо Task.Factory.StartNew.
Сообщение в блоге Стивена Клири и сообщение Стивена Туба, на которое он ссылается, объясняют различия. В этом ответе также есть обсуждение .
источник
Получая доступ,
Task.Result
вы фактически выполняете аналогичную логикуtask.wait
источник
Повторюсь, то, о чем многие уже говорили,
prevTask.Wait()
не нужно .Для получения дополнительных примеров можно перейти к « Объединение задач с помощью задач продолжения» , еще одной ссылке от Microsoft с хорошими примерами.
источник