Release contínuo de um microsserviço com Docker ASP.net core e Azure Containe...
Programação assíncrona com C#
1. Programação assíncrona
com C# 5
Giovanni Bassi
giovanni@lambda3.com.br
@giovannibassi
blog.lambda3.com.br
2. Giovanni Bassi
• Trouxe a Scrum.org, PSM e PSD pro Brasil
• Palestrante nacional e internacional (gestão,
agile, engenharia e arquitetura de software)
• Programador
• tecnoretorica.com.br, blog.lambda3.com.br,
dotnetarchitects.net
• Escalador e ciclista
• Não gerente
6. Tendências
• Aplicações cada vez mais conectadas
– Mais latência
– Mais problemas de responsividade da interface gráfica
(IG)
– Mais problemas de escalabilidade
• Programação assíncrona
– Está se tornando a norma em aplicações escaladas e
responsivas
– APIs que são somente assíncronas, como JavaScript,
Silverlight, Windows 8, Windows Phone
8. O que há de novo?
• Programação assíncrona • Programação assíncrona
• Atributos de informação de • Atributos de informação de
chamada chamada
• Iterators
9. Assincronia em poucas palavras
• Síncrono Espero o resultado antes de retonar
– string DownloadString(...);
• Assíncrono Retorne agora, chame de volta com o
resultado
– void DownloadStringAsync(..., Action<string> callback);
• Benefícios da assincronia
– Responsividade da interface gráfica: libera as threads de IG
para interação com o usuário
– Escalabilidade do servidor: A thread pode ser reutilizada para
outras requisições
10. Síncrono versus Assíncrono
var data = DownloadData(...);
ProcessData(data);
DownloadDataAsync(... , data => {
ProcessData(data);
});
11. Síncrono versus Assíncrono
var data = DownloadData(...);
ProcessData(data);
DownloadDataAsync(... , data => {
ProcessData(data);
});
13. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
Mensagens
Thread de IG
14. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
15. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
16. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
17. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1
18. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
19. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
20. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
21. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
22. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
23. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
24. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
25. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
26. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
27. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
28. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
29. Fluxo de controle assíncrono
async void DoWorkAsync() {
var t1 = ProcessFeedAsync("www.acme.com/rss");
var t2 = ProcessFeedAsync("www.xyznews.com/rss");
await Task.WhenAll(t1, t2);
DisplayMessage("Done");
} async Task ProcessFeedAsync(string url) {
var text = await DownloadFeedAsync(url);
var doc = ParseFeedIntoDoc(text);
await SaveDocAsync(doc);
ProcessLog.WriteEntry(url);
}
t1 t2
30. Como funciona?
async Task<XElement> GetRssAsync(string url) {
var client = new WebClient();
var task = client.DownloadStringTaskAsync(url);
var text = await task;
var xml = XElement.Parse(text);
return xml;
}
31. Como funciona?
async Task<XElement> GetRssAsync(string url) {
var client = new WebClient();
var task = client.DownloadStringTaskAsync(url);
var text = await task;
var xml = XElement.Parse(text);
return xml;
} Task<XElement> GetRssAsync(string url) {
var client = new WebClient();
var task = client.DownloadStringTaskAsync(url);
return task.ContinueWith(delegate
{
var text = task.Result;
var xml = XElement.Parse(text);
return xml;
});
}
32.
33. Como funciona?
Task<XElement> GetRssAsync(string url) {
var $builder = AsyncTaskMethodBuilder<XElement>.Create();
async Task<XElement> $state = 0;
var
TaskAwaiter<string> $a1;
GetRssAsync(string url) {
Action $resume = delegate {
var client = new try {
WebClient();
var task = if ($state == 1) goto L1;
client.DownloadStringTaskAsync(url);new WebClient();
var client =
var text = await task; task = client.DownloadStringTaskAsync(url);
var
$a1 = task.GetAwaiter();
var xml = XElement.Parse(text);
return xml; if ($a1.IsCompleted) goto L1;
} $state = 1;
$a1.OnCompleted($resume);
return;
L1: var text = $a1.GetResult();
var xml = XElement.Parse(text);
$builder.SetResult(xml);
}
catch (Exception $ex) { $builder.SetException($ex); }
};
$resume();
return $builder.Task;
}
34. Como funciona?
Task<XElement> GetRssAsync(string url) {
var $builder = AsyncTaskMethodBuilder<XElement>.Create();
async Task<XElement> $state = 0;
var
TaskAwaiter<string> $a1;
GetRssAsync(string url) {
Action $resume = delegate {
var client = new try {
WebClient();
var task = if ($state == 1) goto L1;
client.DownloadStringTaskAsync(url);new WebClient();
var client =
var text = await task; task = client.DownloadStringTaskAsync(url);
var
$a1 = task.GetAwaiter();
var xml = XElement.Parse(text);
return xml; if ($a1.IsCompleted) goto L1;
} $state = 1;
$a1.OnCompleted($resume);
return;
L1: var text = $a1.GetResult();
var xml = XElement.Parse(text);
$builder.SetResult(xml);
}
catch (Exception $ex) { $builder.SetException($ex); }
};
$resume();
return $builder.Task;
}
35. Como funciona?
Task<XElement> GetRssAsync(string url) {
var $builder = AsyncTaskMethodBuilder<XElement>.Create();
async Task<XElement> $state = 0;
var
TaskAwaiter<string> $a1;
GetRssAsync(string url) {
Action $resume = delegate {
var client = new try {
WebClient();
var task = if ($state == 1) goto L1;
client.DownloadStringTaskAsync(url);new WebClient();
var client =
var text = await task; task = client.DownloadStringTaskAsync(url);
var
$a1 = task.GetAwaiter();
var xml = XElement.Parse(text);
return xml; if ($a1.IsCompleted) goto L1;
} $state = 1;
$a1.OnCompleted($resume);
return;
L1: var text = $a1.GetResult();
var xml = XElement.Parse(text);
$builder.SetResult(xml);
}
catch (Exception $ex) { $builder.SetException($ex); }
};
$resume();
return $builder.Task;
}
36. Como funciona?
Task<XElement> GetRssAsync(string url) {
var $builder = AsyncTaskMethodBuilder<XElement>.Create();
async Task<XElement> $state = 0;
var
TaskAwaiter<string> $a1;
GetRssAsync(string url) {
Action $resume = delegate {
var client = new try {
WebClient();
var task = if ($state == 1) goto L1;
client.DownloadStringTaskAsync(url);new WebClient();
var client =
var text = await task; task = client.DownloadStringTaskAsync(url);
var
$a1 = task.GetAwaiter();
var xml = XElement.Parse(text);
return xml; if ($a1.IsCompleted) goto L1;
} $state = 1;
$a1.OnCompleted($resume);
return;
L1: var text = $a1.GetResult();
var xml = XElement.Parse(text);
$builder.SetResult(xml);
}
catch (Exception $ex) { $builder.SetException($ex); }
};
$resume();
return $builder.Task;
}
37. Métodos assíncronos...
• São marcados com o novo modificador “async”
• Devem retornar void, Task ou Task<T>
• Usam o operador “await” para devolver controle
cooperativamente
• Voltam a ser executados quando uma operação que estava em
espera (await) conclui
• Podem esperar (await) qualquer coisa que implemente o
“padrão de espera”
• Executam no contexto de sincronização de quem os chamou
• Permitem composição com as construções normais de
programação
• Parecem com código normal e síncrono!
39. Async com ASP.NET ontem
public void AcaoAsync()
{
AsyncManager.OutstandingOperations.Increment(5);
var svc = new AsyncPatternSvc.Service1Client();
AsyncManager.Parameters["textoFinal"] = "";
svc.GetDataCompleted += (sender, args) =>
{
AsyncManager.Parameters["textoFinal"] =
((string)AsyncManager.Parameters["textoFinal"]) + args.Result + ", ";
AsyncManager.OutstandingOperations.Decrement();
};
for (int i = 0; i < 5; i++)
svc.GetDataAsync(i);
}
public ActionResult AcaoCompleted(string textoFinal)
{
return View("RetornoServico", new AsyncModel { Resultado = textoFinal });
}
40. Async com ASP.NET hoje
public async Task<ActionResult> Acao()
{
var svc = new TaskSvc.Service1Client();
var resultados = await Task.WhenAll(
from i in Enumerable.Range(0, 5)
select svc.GetDataAsync(i));
var textoFinal = string.Join(", ", resultados);
return View("RetornoServico", new AsyncModel{
Resultado = textoFinal });
}
41. Suporte no .NET Framework
Outras…
Windows
Presentation ASP.NET
Foundation
43. Escalabilidade: Evitando novas threads
• Blocos síncronos lógicos esperando por requisições de
rede:
var feeds = (from url in urls select client.DownloadFeed(url)).ToArray();
var feeds = await Task.WhenAll(from url in urls select client.DownloadFeedAsync(url));
Sem novas threads!
44. Unificando a assincronia
• Um cenário assíncrono
– Busca alguns links de vídeo no YouTube
– Baixa dois vídeos ao mesmo tempo
– Cria um novo vídeo a partir dos vídeos baixados
– Salva o vídeo resultante
46. Métodos assíncronos
• (Quase) tão simples quanto código síncrono
• Unifica assincronia computacional, de rede e de
E/S
• Permite servidores mais escaláveis
• IG mais responsiva
47. Obrigado!
Giovanni Bassi
giovanni@lambda3.com.br
@giovannibassi
blog.lambda3.com.br