Когда использовать 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";

    }