Когда использовать Task.Delay, когда использовать Thread.Sleep?
Есть ли хорошие правила для использования Task.Delay против Thread.Sleep?
- В частности, существует ли минимальное значение для обеспечения эффективности/эффективности над другим?
- Наконец, поскольку Task.Delay вызывает переключение контекста на машине состояния async/wait, есть ли накладные расходы на ее использование?
Ответы
Ответ 1
Используйте Thread.Sleep
, если вы хотите заблокировать текущий поток.
Используйте Task.Delay
, если вы хотите логическую задержку, не блокируя текущий поток.
Эффективность не должна быть главной заботой этих методов. Их основное использование в реальном времени - это таймеры повтора для операций ввода-вывода, которые составляют порядка секунд, а не миллисекунд.
Ответ 2
Самая большая разница между Task.Delay
и Thread.Sleep
заключается в том, что Task.Delay
предназначен для асинхронного запуска. Не имеет смысла использовать Task.Delay
в синхронном коде. ОЧЕНЬ плохая идея использовать Thread.Sleep
в асинхронном коде.
Обычно вы вызываете Task.Delay()
с ключевым словом await
:
await Task.Delay(5000);
или, если вы хотите запустить код до задержки:
var sw = new Stopwatch();
sw.Start();
Task wait = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await wait;
Угадайте, что это будет печатать? Запуск за 0.0070048 секунд.
Если мы переместим await wait
выше Console.WriteLine
, он будет печатать Запуск за 5.0020168 секунд.
Посмотрим на разницу с Thread.Sleep
:
class Program
{
static void Main(string[] args)
{
Task wait = asyncTask();
syncCode();
wait.Wait();
Console.ReadLine();
}
static async Task asyncTask()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("async: Starting");
Task wait = Task.Delay(5000);
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
await wait;
Console.WriteLine("async: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("async: Done");
}
static void syncCode()
{
var sw = new Stopwatch();
sw.Start();
Console.WriteLine("sync: Starting");
Thread.Sleep(5000);
Console.WriteLine("sync: Running for {0} seconds", sw.Elapsed.TotalSeconds);
Console.WriteLine("sync: Done");
}
}
Попробуйте предсказать, что это будет печатать...
async: начиная с async: работает за 0.0070048 секунд
sync: Начиная с async: Запуск за 5.0119008 секунд
async: Готово
синхронизация: Запуск за 5.0020168 секунд
sync: Done
Кроме того, интересно заметить, что Thread.Sleep
гораздо точнее, точность ms не является проблемой, а Task.Delay
может занимать минимум 15-30 мс. Накладные расходы по обеим функциям минимальны по сравнению с точностью, которую они имеют (используйте Stopwatch
Класс, если вам нужно что-то более точное). Thread.Sleep
по-прежнему связывает ваш поток, Task.Delay
отпустите его, чтобы выполнить другую работу, пока вы ждете.
Ответ 3
если текущий поток убит, и вы используете Thread.Sleep
, и он выполняется, тогда вы можете получить ThreadAbortException
.
С помощью Task.Delay
вы всегда можете указать токен отмены и изящно убить его. Это одна из причин, по которой я бы выбрал Task.Delay
. см. http://social.technet.microsoft.com/wiki/contents/articles/21177.visual-c-thread-sleep-vs-task-delay.aspx
Я также согласен, что эффективность в этом случае не имеет первостепенного значения.
Ответ 4
Я хочу кое-что добавить. На самом деле Task.Delay
- это механизм ожидания, основанный на таймере. Если вы посмотрите на источник, вы найдете ссылку на класс Timer
который отвечает за задержку. С другой стороны, Thread.Sleep
фактически Thread.Sleep
текущий поток в спящий режим, таким образом, вы просто блокируете и тратите один поток. В модели асинхронного программирования вы всегда должны использовать Task.Delay()
если хотите, чтобы что-то (продолжение) произошло после некоторой задержки.
Ответ 5
Я хочу отложить возврат просмотра в методе удаления. Является ли использование Thread.sleep хорошим способом? Мне нужно сделать это, чтобы дать время для анимации интерфейса (1500 мс).
Мой контроллер:
@RequestMapping(value = "/delete_client/{clientId}")
public String deleteClient(@PathVariable String clientId, @ModelAttribute("deleteClient") Client client) {
client.setId(clientId);
clientRepository.delete(client);
try {
Thread.sleep(1600);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "redirect:/clients";
}