Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
38m 57s
A programação assíncrona pode parecer intimidante devido à sua terminologia complexa, mas oferece benefícios significativos, tornando os aplicativos mais rápidos e responsivos. O vídeo de Tim Corey sobre " C# Async/Await - Torne seu aplicativo mais responsivo e rápido com programação assíncrona " fornece um guia prático sobre como usar esses recursos de forma eficaz.
Neste artigo, usaremos o vídeo detalhado de Tim Corey para explicar esses conceitos, demonstrando as aplicações práticas de async e await por meio de exemplos claros. Abordaremos diversos cenários, desde manipuladores de eventos assíncronos até o gerenciamento de múltiplas tarefas, contextos de sincronização, tratamento de erros e as armadilhas comuns, como o uso de métodos assíncronos com a propriedade void. Ao final deste artigo, você terá um sólido entendimento de programação assíncrona e de como implementá-la em suas próprias aplicações C#.
A programação assíncrona em C# é essencial para melhorar o desempenho das aplicações, especialmente ao trabalhar com operações que dependem muito de E/S ou de CPU. As palavras-chave async e await permitem que os desenvolvedores escrevam código assíncrono que pode executar tarefas de longa duração sem bloquear o thread principal. Ao marcar um método com a palavra-chave async, você sinaliza que o método realizará uma operação assíncrona, retornando um Task ou Task<t>. A palavra-chave await é usada dentro de um método assíncrono para pausar a execução até que a tarefa aguardada seja concluída, permitindo que outras operações sejam executadas simultaneamente.
Ao contrário da programação síncrona, em que as tarefas são executadas sequencialmente e podem bloquear a thread de chamada, os métodos assíncronos permitem lidar com várias tarefas simultaneamente, como processos em segundo plano ou processamento de entrada do usuário, sem congelar a thread da interface do usuário. Neste artigo, exploraremos como async e await funcionam juntos, cobrindo conceitos como métodos async void, tratamento de erros, trocas de contexto e contextos de sincronização. Você aprenderá como gerenciar com eficiência múltiplas operações assíncronas e lidar com exceções, garantindo uma execução tranquila em toda a thread de chamada, thread da interface do usuário e conclusão da tarefa. Essa abordagem é particularmente útil em cenários que envolvem sistemas de arquivos, solicitações de rede ou solicitações simultâneas, onde a capacidade de resposta é fundamental.
Tim introduz a programação assíncrona explicando a diferença entre operações síncronas e assíncronas. Na programação síncrona, as tarefas são executadas sequencialmente, causando atrasos se uma tarefa demorar muito. A programação assíncrona permite que as tarefas sejam executadas em paralelo ou em segundo plano, melhorando o desempenho e a capacidade de resposta.
Tim destaca dois benefícios principais da programação assíncrona:
Melhoria na capacidade de resposta da interface do usuário (IU) : Ao executar tarefas de forma assíncrona, a IU permanece responsiva mesmo durante a execução de operações demoradas.
Execução paralela : Tarefas independentes podem ser executadas em paralelo, reduzindo o tempo total necessário para concluí-las.
Tim configura um aplicativo de demonstração do Windows Presentation Foundation (WPF) para demonstrar a diferença entre operações síncronas e assíncronas. O aplicativo possui dois botões: um para executar tarefas de forma síncrona e outro para executá-las de forma assíncrona.

O aplicativo também inclui um painel de resultados para exibir a saída.
Tim explica o código por trás da operação síncrona. Um Stopwatch é usado para medir o tempo de execução da tarefa.
private void ExecuteSync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
List<string> websites = GetWebsiteList();
foreach (var website in websites)
{
string result = DownloadWebsite(website);
ReportWebsiteInfo(website, result);
}
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
private List<string> GetWebsiteList()
{
return new List<string>
{
"https://www.yahoo.com",
"https://www.google.com",
"https://www.microsoft.com",
"https://www.cnn.com",
"https://www.codeproject.com",
"https://www.stackoverflow.com"
};
}
private string DownloadWebsite(string websiteURL)
{
WebClient client = new WebClient();
return client.DownloadString(websiteURL);
}
private void ReportWebsiteInfo(string website, string data)
{
ResultsWindow.Text += $"{website}: {data.Length} characters{Environment.NewLine}";
}Private Sub ExecuteSync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Dim websites As List(Of String) = GetWebsiteList()
For Each website In websites
Dim result As String = DownloadWebsite(website)
ReportWebsiteInfo(website, result)
Next
stopwatch.Stop()
ResultsWindow.Text &= $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End Sub
Private Function GetWebsiteList() As List(Of String)
Return New List(Of String) From {
"https://www.yahoo.com",
"https://www.google.com",
"https://www.microsoft.com",
"https://www.cnn.com",
"https://www.codeproject.com",
"https://www.stackoverflow.com"
}
End Function
Private Function DownloadWebsite(websiteURL As String) As String
Dim client As New WebClient()
Return client.DownloadString(websiteURL)
End Function
Private Sub ReportWebsiteInfo(website As String, data As String)
ResultsWindow.Text &= $"{website}: {data.Length} characters{Environment.NewLine}"
End SubEste código executa os seguintes passos:
Tim executa o aplicativo para demonstrar a operação síncrona. Ele observa que a interface do usuário deixa de responder enquanto os sites estão sendo baixados e que os resultados são exibidos todos de uma vez após a conclusão dos downloads.

Para uma demonstração prática da forma imóvel, assista ao vídeo para melhor compreensão a partir de 9:20.
Tim resolve o primeiro problema convertendo o método síncrono em um método assíncrono. Isso envolve o uso das palavras-chave async e await. Segue uma explicação passo a passo do processo:
Copiar método síncrono existente : Tim copia o método síncrono existente e renomeia-o para indicar que ele será assíncrono.
private async Task RunDownloadAsync()
{
// Same code as RunDownloadSync, but will be modified for async
}
Modificar a chamada de download para execução assíncrona :
Task.Run para executá-la assíncronamente.private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
return await Task.Run(() => DownloadWebsite(websiteURL));
}
await garante que o método espere que a tarefa assíncrona seja concluída antes de continuar.Certifique-se de que o método seja assíncrono :
async, e ela retorna um Task.private async Task RunDownloadAsync()
{
List<string> websites = GetWebsiteList();
foreach (var website in websites)
{
var result = await DownloadWebsiteAsync(website);
ReportWebsiteInfo(website, result);
}
}
Lide com o evento corretamente :
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
Observe que os manipuladores de eventos podem retornar void mesmo que chamem métodos assíncronos.
Tim mostra que, ao usar a palavra-chave await, a interface do usuário permanece responsiva. Isso permite que os usuários interajam com a janela enquanto a tarefa assíncrona está em execução.
// UI remains responsive
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}' UI remains responsive
Private Async Sub ExecuteAsync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Await RunDownloadAsync()
stopwatch.Stop()
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End SubPara garantir que o tempo total de execução seja relatado corretamente, Tim adiciona a palavra-chave await à chamada no manipulador de eventos de clique do botão.
// Correctly waits for the asynchronous task to complete
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}' Correctly waits for the asynchronous task to complete
Private Async Sub ExecuteAsync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Await RunDownloadAsync()
stopwatch.Stop()
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End SubAo aguardar a conclusão do método assíncrono, o tempo de execução é medido com precisão e os resultados são exibidos à medida que são obtidos.
Tim aborda a limitação de esperar que cada tarefa seja concluída sequencialmente, utilizando a execução paralela. Eis como ele modifica o código para conseguir isso:
Copie o método assíncrono existente : Tim duplica o método assíncrono existente e o renomeia para indicar execução paralela.
private async Task RunDownloadParallelAsync()
{
// Parallel execution logic will be added here
}
Criar uma lista de tarefas :
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();Dim tasks As New List(Of Task(Of WebsiteDataModel))()Iniciar todas as tarefas sem esperar : Em vez de aguardar cada tarefa de download imediatamente, Tim as adiciona à lista de tarefas.
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
Aguarde a conclusão de todas as tarefas :
Task.WhenAll é usado para aguardar a conclusão de todas as tarefas. Este método retorna uma matriz de resultados assim que todas as tarefas forem concluídas.WebsiteDataModel[] results = await Task.WhenAll(tasks);Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)Processar os resultados : Após a conclusão de todas as tarefas, Tim processa os resultados em um loop.
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
Segue o código completo para o método de execução paralela:
private async Task RunDownloadParallelAsync()
{
List<string> websites = GetWebsiteList();
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
WebsiteDataModel[] results = await Task.WhenAll(tasks);
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
}Private Async Function RunDownloadParallelAsync() As Task
Dim websites As List(Of String) = GetWebsiteList()
Dim tasks As New List(Of Task(Of WebsiteDataModel))()
For Each website As String In websites
tasks.Add(DownloadWebsiteAsync(website))
Next
Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)
For Each result As WebsiteDataModel In results
ReportWebsiteInfo(result)
Next
End FunctionTim atualiza o manipulador de eventos de clique do botão para chamar o novo método de execução paralela.
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadParallelAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}Private Async Sub ExecuteAsync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Await RunDownloadParallelAsync()
stopwatch.Stop()
ResultsWindow.Text &= $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End SubAo esperar por RunDownloadParallelAsync, o tempo total de execução é medido e relatado com precisão.
Tim demonstra a melhoria de desempenho executando o aplicativo em paralelo. Os resultados mostram uma redução significativa no tempo total de execução em comparação com a execução sequencial.
// Parallel execution
async Task RunDownloadParallelAsync();' Parallel execution
Async Function RunDownloadParallelAsync() As Task
End FunctionO aumento de velocidade é evidente, pois os sites são baixados simultaneamente, reduzindo o tempo total de espera à duração do download individual mais lento.
Task.Run() vs Chamada de Método AssíncronoTim explica o conceito de usar Task.Run() para envolver um método síncrono e torná-lo assíncrono quando você não pode modificar o método original. No entanto, ele também mostra a abordagem preferida de modificar o próprio método para ser assíncrono, caso você tenha controle sobre ele.
Envolvendo Método em Task.Run():
Essa abordagem é útil quando você não pode alterar o código do método original, mas ainda deseja executá-lo de forma assíncrona.
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
return await Task.Run(() => DownloadWebsite(websiteURL));
}
Tornando um método assíncrono :
Se for possível modificar o método, é melhor convertê-lo para assíncrono usando uma API assíncrona apropriada.
Tim demonstra isso alterando DownloadWebsite para DownloadWebsiteAsync e usando DownloadStringTaskAsync de WebClient.
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
WebClient client = new WebClient();
string data = await client.DownloadStringTaskAsync(websiteURL);
return new WebsiteDataModel { URL = websiteURL, Data = data };
}
Ajustando o método de chamada :
Task.Run() e chamar diretamente o método assíncrono.private async Task RunDownloadParallelAsync()
{
List<string> websites = GetWebsiteList();
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
WebsiteDataModel[] results = await Task.WhenAll(tasks);
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
}Private Async Function RunDownloadParallelAsync() As Task
Dim websites As List(Of String) = GetWebsiteList()
Dim tasks As New List(Of Task(Of WebsiteDataModel))()
For Each website As String In websites
tasks.Add(DownloadWebsiteAsync(website))
Next
Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)
For Each result As WebsiteDataModel In results
ReportWebsiteInfo(result)
Next
End FunctionTim conclui com vários pontos importantes sobre o uso de async e await:
Garantir Métodos Retornando Tasks: Sempre que você marcar um método como async, ele deve retornar um Task ou Task<t> em vez de void (exceto para manipuladores de eventos).
Use await para Operações Confiáveis: Use a palavra-chave await quando você precisar do resultado de uma operação assíncrona antes de prosseguir.
Envolvimento de Tarefa para Código Não Modificável: Use Task.Run() para envolver métodos síncronos quando não puder modificar o método original.
Marcar Métodos Assíncronos Apropriadamente: Sempre adicione Async ao nome do método para indicar que é uma operação assíncrona.
Execução paralela versus sequencial : Decida se as tarefas podem ser executadas em paralelo ou se devem esperar umas pelas outras, com base nas dependências entre elas.
Tim enfatiza que a programação assíncrona em C# foi simplificada com async, await e Task. Complexidades como contextos de threading e modelos de apartamento são gerenciadas nos bastidores.
O tutorial de Tim Corey sobre async e await em C# oferece um recurso inestimável para dominar a programação assíncrona. Ao explicar cuidadosamente conceitos como paralelismo de tarefas, responsividade da interface do usuário e a importância de usar async e await no contexto correto, Tim fornece aos desenvolvedores as ferramentas para criar aplicativos mais rápidos e responsivos. Seu passo a passo detalhado demonstra como lidar de forma eficiente com tarefas de longa duração sem bloquear a thread principal, além de estratégias para gerenciar operações assíncronas e execução paralela.
Para uma compreensão mais aprofundada e exemplos práticos adicionais, recomendo vivamente que veja o vídeo de Tim Corey. Suas ideias sobre métodos assíncronos e vazios, tratamento de erros e gerenciamento de contextos de sincronização aprimorarão ainda mais sua capacidade de implementar esses conceitos em seus projetos.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy