Programação assíncrona com C#

2,631 views
2,462 views

Published on

Palestra ministrada no TDC 2012 em Goiânia

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,631
On SlideShare
0
From Embeds
0
Number of Embeds
371
Actions
Shares
0
Downloads
0
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Programação assíncrona com C#

  1. 1. Programação assíncrona com C# 5 Giovanni Bassi giovanni@lambda3.com.br @giovannibassi blog.lambda3.com.br
  2. 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
  3. 3. http://bit.ly/lambda3democracia
  4. 4. Evolução do C# e VB C# 4.0 + VB 10.0 Dinamismo + paridade nas linguagens C# 3.0 + VB 9.0 Language Integrated Query C# 2.0 + VB 8.0 GenericsC# 1.0 + VB 7.0 Código gerenciado
  5. 5. Tendências
  6. 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
  7. 7. Evolução do C# e VB C# 5.0 + VB 11.0 Programação assíncrona C# 4.0 + VB 10.0 Dinamismo + paridade nas linguagens C# 3.0 + VB 9.0 Language Integrated Query C# 2.0 + VB 8.0 GenericsC# 1.0 + VB 7.0 Código gerenciado
  8. 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. 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. 10. Síncrono versus Assíncronovar data = DownloadData(...);ProcessData(data);DownloadDataAsync(... , data => { ProcessData(data);});
  11. 11. Síncrono versus Assíncronovar data = DownloadData(...);ProcessData(data);DownloadDataAsync(... , data => { ProcessData(data);});
  12. 12. Interface gráficaassíncrona e responsiva
  13. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 32. 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; }
  33. 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. 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. 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. 36. 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!
  37. 37. Depurando métodosassíncronos
  38. 38. Async com ASP.NET ontempublic 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 });}
  39. 39. Async com ASP.NET hojepublic 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 });}
  40. 40. Suporte no .NET Framework Outras…WindowsPresentation ASP.NETFoundation
  41. 41. WCF – Cliente/Servidor
  42. 42. 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!
  43. 43. 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
  44. 44. Unificando a assincroniatry { string[] videoUrls = await ScrapeYoutubeAsync(url); // Rede Task<Video> t1 = DownloadVideoAsync(videoUrls[0]); // Baixe 2 videos Task<Video> t2 = DownloadVideoAsync(videoUrls[1]); Video[] vids = await Task.WhenAll(t1, t2); // Espere os 2 Video v = await MashupVideosAsync(vids[0], vids[1]); // CPU await v.SaveAsync(textbox.Text); // Entrada/Saída}catch (WebException ex) { ReportError(ex);}
  45. 45. 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
  46. 46. Obrigado! Giovanni Bassi giovanni@lambda3.com.br @giovannibassi blog.lambda3.com.br

×