C# - Thread.Sleep x Task.Delay


 Neste artigo vamos comparar a utilização de Thread.Sleep com Task.Delay para dar uma pausa na linguagem c#.

Quando precisamos dar uma pausa em um código C# podemos usar Thread.Sleep ou Task.Delay para suspender a execução de um programa por algum tempo.

À primeira vista o efeito é o mesmo e parece ser indiferente preferir este ou aquele método.

Mas será que é isso mesmo ?  

Será que estamos realmente suspendendo a execução do código usando os dois métodos ?

Qual seria a diferença entre esses dois ?

Se você nunca pensou nisso antes vamos tentar responder essas perguntas neste artigo.

Recursos Usados

Comparando Thread.Sleep com Task.Delay

Vamos criar um projeto bem simples do tipo Windows Forms usando a linguagem C#.

No formulário Form1.cs inclua 3 Botões de comando conforme mostra a figura abaixo:



A seguir inclua o seguinte código no formulário :

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WF_Delay
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        void PausaComThreadSleep()
        {
            Thread.Sleep(5000);
        }
        async Task PausaComTaskDelay()
        {
            await Task.Delay(5000);
        }
        private void btnThreadSleep_Click(object sender, EventArgs e)
        {
            PausaComThreadSleep();
            MessageBox.Show("Retornando da pausa...Thread.Sleep");
        }
        private async void btnTaskDelay_Click(object sender, EventArgs e)
        {
            await PausaComTaskDelay();
            MessageBox.Show("Retornando da pausa...Task.Delay");
        }
    }
}

Deixamos o código o mais simples possível para você entender. Se você não conhece o conceito de Task/await/async leia os artigos publicados e indicados nas referências.

Ao executar o projeto e clicar no primeiro botão você verá a exibição de uma mensagem após 5 segundos. Você terá o mesmo comportamento ao clicar no segundo botão.

Então podemos concluir que Thread.Sleep é igual a Task.Delay ?

Não é bem assim...

Vejamos então as diferenças.

1- Thread.Sleep()

Usar Thread.Sleep é a maneira clássica de suspender uma execução.

Este método irá suspender o thread atual até o tempo definido decorrer.

Quando você utiliza o recurso Thread.Sleep da maneira acima, não há nada que você possa fazer para abortar a pausa, e vai ter que aguardar o tempo decorrido ou reiniciar a aplicação.

Isso ocorre porque você esta suspendendo a thread principal que o programa está executando.

E por isso a interface de usuário (UI) não responde.

2- Task.Delay()

A Task.Delay() atua de maneira diferente.

Basicamente, Task.Delay() vai criar uma tarefa que será completada após o tempo definido ser decorrido.

Esta tarefa será executada em um segmento diferente, e a interface de usuário (IU) vai estar responsiva.

Esse comportamento ocorre porque Task.Delay() não está bloqueando a thread principal.

Cancelando a Pausa

Vejamos agora como podemos cancelar a pausa. Como já vimos isso somente é possível para Task.Delay.

Vamos alterar o código do método PausaComTaskDekay conforme mostrado a seguir:

         ...
        CancellationTokenSource tokenSource = new CancellationTokenSource();

        async Task PausaComTaskDelay()
        {
            try
            {
                await Task.Delay(5000, tokenSource.Token);
            }
            catch (TaskCanceledException ex)
            {
                  MessageBox.Show("A Pausa foi cancelada...");
            }
            catch (Exception ex)
            {
               
            }
        }
      .....

Neste código estamos criando uma instância da classe CancellationTokenSource que sinaliza para um token que ele deve ser cancelado.

Será lançada uma exceção no cancelamento onde estamos exibindo uma mensagem que a mensagem foi cancelada.

A seguir na chamada da tarefa usamos o tokenSource com o token de cancelamento associado.

Agora para isso funcionar vamos definir o código no evento click do botão para cancelar a pausa:

 private void btnCancelarPausa_Click(object sender, EventArgs e)
 {
      tokenSource.Cancel();
 }

No código estamos comunicando o token para cancelamento que será usado em Task.Delay.

Executando o projeto e cancelando a pausa teremos:

E estamos conversados...

"Jesus disse-lhes: A minha comida é fazer a vontade daquele que me enviou, e realizar a sua obra."
João 4:34

Referências:


José Carlos Macoratti