private void BtnProcessar_Click_Bloqueando(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; BtnProcessar1.IsEnabled = false; BtnProcessar2.IsEnabled = false; BtnProcessar3.IsEnabled = false; var textoInicial = BtnProcessar2.Content; BtnProcessar2.Content = "Processando..."; var contas = r_Repositorio.GetContaClientes(); var resultado = new List <string>(); LimparView(); var inicio = DateTime.Now; foreach (var conta in contas) { var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); } var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; BtnProcessar1.IsEnabled = true; BtnProcessar2.IsEnabled = true; BtnProcessar3.IsEnabled = true; BtnProcessar2.Content = textoInicial; }
private void BtnProcessar_Click(object sender, RoutedEventArgs e) { var taskSchedulerUI = TaskScheduler.FromCurrentSynchronizationContext(); //Pegar a task scheduler da UI está em execução BtnProcessar.IsEnabled = false; var contas = r_Repositorio.GetContaClientes(); var resultado = new List <string>(); AtualizarView(new List <string>(), TimeSpan.Zero); var inicio = DateTime.Now; var contaTarefas = contas.Select(conta => { return(Task.Factory.StartNew(() => { var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); })); }).ToArray();//O ToArray() serve para a execução do linq //Task.WaitAll(contaTarefas); Task.WhenAll(contaTarefas).ContinueWith(task => { var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); }); }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> progresso, CancellationToken ct) { var tasks = contas.Select(conta => { return(Task.Factory.StartNew(() => { if (ct.IsCancellationRequested) { throw new OperationCanceledException(ct); } var consolidacao = r_Servico.ConsolidarMovimentacao(conta); progresso.Report(consolidacao); if (ct.IsCancellationRequested) { throw new OperationCanceledException(ct); } return consolidacao; }, ct)); }); return(await Task.WhenAll(tasks)); }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportadorDeProgresso, CancellationToken ct) { /* * Parece que algo está estranho, pois estamos retornando uma lista vazia. Até o método ConsolidarContas retornar, * nenhuma tarefa terá o processamento terminado. Na realidade, o que vamos retornar neste método não será uma lista de string, * e sim uma tarefa que retorna uma lista de string. Ainda não vimos uma tarefa com retorno, mas isto é possível, sendo do mesmo * tipo, porém genérico. Vamos utilizá-la como uma lista. Teremos uma task e, entre os sinais de maior e menor, indicamos o * retorno da tarefa correspondente, no caso, uma lista de string. */ var tasks = contas.Select(conta => Task.Factory.StartNew(() => { ct.ThrowIfCancellationRequested(); var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); reportadorDeProgresso.Report(resultadoConsolidacao); ct.ThrowIfCancellationRequested(); return(resultadoConsolidacao); }) ); /* * temos várias tarefas (tasks), todas retornando o mesmo tipo, e com o resultado, teremos uma tarefa que retorna * um array deste tipo. Como podemos utilizar isto? Guardaremos o WhenAll de todas estas tarefas em uma variável. * Aqui, não queremos uma task, e sim o resultado, portanto podemos usar apenas o await, tendo como resultado um * array de string */ return(await Task.WhenAll(tasks)); }
// Retornara uma Tarefa que irá retornar as contas consolidadas private Task <List <string> > ConsolidarContas(IEnumerable <ContaCliente> contas) { var resultado = new List <string>(); // Realizando o mapeamento para que cada conta seja consolidada por uma task, a task será armazenada no array var tasks = contas.Select(conta => { // Para cada conta uma Task será criada e iniciada return(Task.Factory.StartNew(() => { // Realizará a consolidação dessa conta e adicionara o resultado na lista de contas var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); })); }); // Quando todas as tarefas do array de tasks anterior forem terminadas // uma nova task sera executada, que apenas irá retornar o resultado da consolidação // de todas as contas // Task.WhenAll() => retornará uma outra tarefa que só tem a função de esperar as tarefas que são passadas por parametro terminarem (array) return(Task.WhenAll(tasks).ContinueWith(task => { // O retorno da tarefa será o resultado da consolidação return resultado; })); // ContinueWith => Irá encadear outra tarefa após a execução da anterior, ou seja no exemplo acima // só será executada quando a tarefa que espera as tasks do array forem terminadas // task => task que originou a tarefa atual }
private async Task <string[]> ConsolidaContas(IEnumerable <ContaCliente> contas) { var tarefas = contas.Select(conta => Task.Factory.StartNew(() => r_Servico.ConsolidarMovimentacao(conta)) ); return(await Task.WhenAll(tarefas)); }
private void ConsolidarMovimentacao(IEnumerable <ContaCliente> contas) { foreach (var conta in contas) { var resultadoProcessamento = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoProcessamento); } }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas) { var _tasks = contas.Select(conta => Task.Factory.StartNew(() => r_Servico.ConsolidarMovimentacao(conta)) ); var resultado = await Task.WhenAll(_tasks); return(resultado); #region Como realizar sem o Async Await //var _tasks = contas.Select(conta => //{ // return Task.Factory.StartNew(() => // { // var contaResultado = r_Servico.ConsolidarMovimentacao(conta); // resultado.Add(contaResultado); // }); //}).ToArray(); //return Task.WhenAll(_tasks) // .ContinueWith(task => // { // return resultado; // }); #endregion }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportadorDeProgresso, CancellationToken ct) { var tasks = contas.Select(conta => { return(Task.Factory.StartNew(() => { // Verificando se a tarefa foi cancelada em tempo de execução if (ct.IsCancellationRequested) { throw new OperationCanceledException(ct); } var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); // Efetuando a atualização da barra de progresso reportadorDeProgresso.Report(resultadoConsolidacao); // Outra meneira de verificar se a tarefa foi cancelada ct.ThrowIfCancellationRequested(); return resultadoConsolidacao; }, ct)); // Passando o CancellationToken como parametro, para ele não iniciar tarefas caso o usuario tenho cancelado a requisição }); var resultado = await Task.WhenAll(tasks); return(resultado); }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> progress) { var tasks = contas.Select(conta => Task.Factory.StartNew(() => { var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta); progress.Report(resultadoConsolidacao); return(resultadoConsolidacao); })); return(await Task.WhenAll(tasks)); }
// A tarefa de consolidar contas tambem é executada de forma assíncrona e retorna uma tarefa que retorna um array de strings public async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas) { var resultado = new List <string>(); // Para cada conta da lista, eu crio uma task e já a inicio, cada task irá consolidar uma conta dessa lista e retornar uma String (conta consolidada) // a task criada será armazenada em um array de tasks var tasks = contas.Select(conta => Task.Factory.StartNew(() => r_Servico.ConsolidarMovimentacao(conta))); // com await => segue o fluxo desse método até que todas as tasks do array terminem o seu processo // (Como é um array de tarefas, o resultado final será tmb um array de resultados (Strings que representa uma conta consolidada) return(await Task.WhenAll(tasks)); // Retorna uma tarefa que devolve um array de contas consolidadas }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> progress, CancellationToken ct) { var tarefas = contas.Select(conta => Task.Factory.StartNew(() => { ct.ThrowIfCancellationRequested(); var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); ct.ThrowIfCancellationRequested(); progress.Report(resultadoConsolidacao); return(resultadoConsolidacao); }, ct)); return(await Task.WhenAll(tarefas)); }
private async Task <int> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportProgressUser, CancellationToken ct) { var totalProcessado = 0; var tasks = contas.Select(conta => Task.Factory.StartNew(() => { ct.ThrowIfCancellationRequested(); var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); ct.ThrowIfCancellationRequested(); reportProgressUser.Report(resultadoConsolidacao); totalProcessado++; }, ct)); await Task.WhenAll(tasks); return(totalProcessado); }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportadorDeProgresso, CancellationToken ct) { var tasks = contas.Select(conta => Task.Factory.StartNew(() => /*inicia novas tarefas para cada conta. A factory cogerencia as tarefas entre os nucleos do processador*/ { ct.ThrowIfCancellationRequested(); var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); reportadorDeProgresso.Report(resultadoConsolidacao); ct.ThrowIfCancellationRequested(); return(resultadoConsolidacao); }, ct) ); return(await Task.WhenAll(tasks)); /*Só retorna quando todos os processos terminarem*/ }
private Task <List <string> > ConsolidarContas(IEnumerable <ContaCliente> contas) { /* * Parece que algo está estranho, pois estamos retornando uma lista vazia. Até o método ConsolidarContas retornar, * nenhuma tarefa terá o processamento terminado. Na realidade, o que vamos retornar neste método não será uma lista de string, * e sim uma tarefa que retorna uma lista de string. Ainda não vimos uma tarefa com retorno, mas isto é possível, sendo do mesmo * tipo, porém genérico. Vamos utilizá-la como uma lista. Teremos uma task e, entre os sinais de maior e menor, indicamos o * retorno da tarefa correspondente, no caso, uma lista de string. */ var resultado = new List <string>(); var tasks = contas.Select(conta => { //estou criando uma task por conta cliente. return(Task.Factory.StartNew(() => { /* * Sempre que temos uma tarefa encadeando outra, por parâmetro, recebemos a tarefa anterior, finalizada. */ var contaResulado = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(contaResulado); })); }); /* SOBRECARGA continueWith: a primeira devolve uma task, a segunda um tipo generico * Como retornaremos uma tarefa que por sua vez retorna uma lista e que, na verdade, precisa esperar todas as outras tarefas? * O WhenAll já vai esperar a execução de todas as tarefas. E ainda temos o método ContinueWith, o qual possibilita duas * sobrecargas: uma normal, que retorna uma task, e outra genérica, que retorna uma task com retorno de tipo genérico. Vamos * usar esta construção, e ela receberá um delegate, uma ação, que irá retornar o resultado. Como estamos executando esta tarefa de * forma encadeada em outra (aquela que espera todas as demais serem executadas), neste momento sabemos que o resultado está populado, * bastando retorná-lo. */ //Quando todas as minhas tasks forem executados retornamos a lista de resultados. return(Task.WhenAll(tasks) // O WhenAll vai esperar a execução de todas as tarefas. .ContinueWith(t => { //temos o método ContinueWith, o qual possibilita duas sobrecargas: uma normal, que retorna uma task e outra genérica, que retorna uma task com retorno de tipo genérico /* Sempre que temos uma tarefa encadeando outra, por parâmetro, recebemos a tarefa anterior, finalizada. * * Agora veremos por que isto é importante. Não se trata de uma tarefa qualquer, e sim com retorno de lista de string. * * Teremos portanto uma propriedade disponível chamada task.Result, pois as tarefas que possuem retorno são de classe genérica. */ return resultado; })); }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportadorDeProgresso, CancellationToken ct) { var tasks = contas.Select(conta => Task.Factory.StartNew(() => { // Ponto em que o usuário pode clicar em cancelar // foi escolhido essa posição pois ela antecede um processo pesado que no caso é o // Consolidar Movimentação, o mesmo foi feito para os outros lugares ct.ThrowIfCancellationRequested(); var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); reportadorDeProgresso.Report(resultadoConsolidacao); ct.ThrowIfCancellationRequested(); return(resultadoConsolidacao); }) ); return(await Task.WhenAll(tasks)); }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportadorDeProgresso, CancellationToken ct) { var tasks = contas.Select(conta => Task.Factory.StartNew(() => { ct.ThrowIfCancellationRequested(); var resultadoConsolidação = r_Servico.ConsolidarMovimentacao(conta); reportadorDeProgresso.Report(resultadoConsolidação); ct.ThrowIfCancellationRequested(); return(resultadoConsolidação); }, ct) ); var resultado = await Task.WhenAll(tasks); return(resultado); #region old way // var resultado = new List<string>(); // var tasks = contas.Select(conta => // { // return Task.Factory.StartNew(()=> // { // var contaResultado = r_Servico.ConsolidarMovimentacao(conta); // resultado.Add(contaResultado); // }); //}); // return Task.WhenAll(tasks).ContinueWith(t=> // { // return resultado; // }); #endregion }
private async Task <string[]> ConsolidarContas(IEnumerable <ContaCliente> contas, IProgress <string> reportadorDeProgresso, CancellationToken ct) { var taskSchedulerGUI = TaskScheduler.FromCurrentSynchronizationContext(); var tasks = contas.Select(conta => Task.Factory.StartNew(() => { //if (ct.IsCancellationRequested) // throw new OperationCanceledException(ct); ct.ThrowIfCancellationRequested(); var resultadoConsolidacao = r_Servico.ConsolidarMovimentacao(conta, ct); reportadorDeProgresso.Report(resultadoConsolidacao); //if (ct.IsCancellationRequested) // throw new OperationCanceledException(ct); ct.ThrowIfCancellationRequested(); return(resultadoConsolidacao); }, ct) ); return(await Task.WhenAll(tasks)); }
private void BtnProcessar_Click(object sender, RoutedEventArgs e) { var contas = r_Repositorio.GetContaClientes(); var contasQuantidadePorThread = contas.Count() / 4; var contas_parte1 = contas.Take(contasQuantidadePorThread); var contas_parte2 = contas.Skip(contasQuantidadePorThread).Take(contasQuantidadePorThread); var contas_parte3 = contas.Skip(contasQuantidadePorThread * 2).Take(contasQuantidadePorThread); var contas_parte4 = contas.Skip(contasQuantidadePorThread * 3); var resultado = new List <string>(); AtualizarView(new List <string>(), TimeSpan.Zero); var inicio = DateTime.Now; Thread thread_parte1 = new Thread(() => { foreach (var conta in contas_parte1) { var resultadoProcessamento = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoProcessamento); } }); Thread thread_parte2 = new Thread(() => { foreach (var conta in contas_parte2) { var resultadoProcessamento = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoProcessamento); } }); Thread thread_parte3 = new Thread(() => { foreach (var conta in contas_parte3) { var resultadoProcessamento = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoProcessamento); } }); Thread thread_parte4 = new Thread(() => { foreach (var conta in contas_parte4) { var resultadoProcessamento = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoProcessamento); } }); thread_parte1.Start(); thread_parte2.Start(); thread_parte3.Start(); thread_parte4.Start(); while (thread_parte1.IsAlive || thread_parte2.IsAlive || thread_parte3.IsAlive || thread_parte4.IsAlive) { Thread.Sleep(250); //Não vou fazer nada } var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); }
private void BtnProcessar_Click(object sender, RoutedEventArgs e) { var contas = r_Repositorio.GetContaClientes(); var contasQuantidadePorThread = contas.Count() / 4; // Armazena em um IEnumerable os N Primeiros Elementos da Lista var contas_parte1 = contas.Take(contasQuantidadePorThread); var contas_parte2 = contas.Skip(contasQuantidadePorThread).Take(contasQuantidadePorThread); var contas_parte3 = contas.Skip(contasQuantidadePorThread * 2).Take(contasQuantidadePorThread); var contas_parte4 = contas.Skip(contasQuantidadePorThread * 3); var resultado = new List <string>(); AtualizarView(new List <string>(), TimeSpan.Zero); Thread thread_parte1 = new Thread(() => { foreach (var conta in contas_parte1) { var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); } }); Thread thread_parte2 = new Thread(() => { foreach (var conta in contas_parte2) { var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); } }); Thread thread_parte3 = new Thread(() => { foreach (var conta in contas_parte3) { var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); } }); Thread thread_parte4 = new Thread(() => { foreach (var conta in contas_parte4) { var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); resultado.Add(resultadoConta); } }); var inicio = DateTime.Now; thread_parte1.Start(); thread_parte2.Start(); thread_parte3.Start(); thread_parte4.Start(); while (thread_parte1.IsAlive || thread_parte2.IsAlive || thread_parte3.IsAlive || thread_parte4.IsAlive) { // Pausa a thread principal por alguns millisegundos para que a condição acima não seja verificada a todo momento Thread.Sleep(250); // Enquanto as threads estiverem trabalhando não faço nada } var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); }
/// Clicaremos em "Fazer Processamento" no ByteBank. Lembrem-se que no vídeo anterior só havia um núcleo em funcionamento (CPU 0), e agora temos /// mais um. Ou seja, provavelmente o primeiro que estava sendo utilizado está executando uma thread da aplicação, e o outro (CPU 1), a outra thread. /// Desta forma, teoricamente, a aplicação rodará mais rapidamente - mas isto não é uma regra. Muitos fatores influenciam a velocidade de execução de /// uma aplicação: o sistema operacional pode estar aguardando respostas da rede, tentando ler o disco rígido, entre outros. private void BtnProcessar_Click(object sender, RoutedEventArgs e) { this.Cursor = Cursors.Wait; /* * O erro ocorreu porque estávamos na thread principal, atualizando a lista de resultados (LstResultados) e o texto de resumo (TxtTempo.Text = mensagem) * na mesma thread. Colocamos os códigos criados agora em uma diferente, sem saber qual, cuja responsabilidade não é nossa. Uma thread diferente não pode * acessar o controle da interface gráfica. O .NET protege isto, e quando uma tentativa de acesso a um objeto da interface gráfica ocorre por uma * thread diferente, a aplicação é travada, lançando-se a exceção. * * É necessário informar ao .NET que o código recém criado será executado na interface gráfica, sem ser necessário esperar todas as outras, * mantendo-se a interface gráfica travada até que a execução do código. Lembra que tínhamos um intermediário responsável por delegar quem * executaria qual tarefa, delegando assegurando que todas as threads fossem executadas da forma mais otimizada possível? * * O TaskScheduler também existe na thread principal, sendo obtido a partir de uma que estiver em execução, com o método estático * FromCurrentSynchronizationContext(), que retorna o TaskScheduler atuante no momento. * * Assim, informamos ao .NET nosso desejo de que a tarefa referente à finalização e atualização de visualização seja feita de acordo com a demanda do * TaskScheduler, podendo ser enviado no método ContinueWith, como um parâmetro. */ //Agora esta no contexto da thread principal, se eu mudado para dentro de uma thread lá sera o novo contexto. var taskSchedulerUI = TaskScheduler.FromCurrentSynchronizationContext(); BtnProcessar.IsEnabled = false; //Obtem as contas do usuarios var contas = r_Repositorio.GetContaClientes(); // a porção para cada thread processar var contasQuantidadePorThread = contas.Count() / 4; //Atualiza a lista AtualizarView(new List <string>(), TimeSpan.Zero); //Inicio do processamento var inicio = DateTime.Now; /*================================= * -- TaskScheduler --------------- * ================================ * É gestor de tarefas do .Net. Agora nao precisamos mais nos preocuprar a performance das Threads, * ou quais sao as boas praticas. O task e excutado em um alto niveil. Thread baixo nivel. OS. * * Se há 10 contas sendo executadas simultaneamente, e 8 núcleos, sendo que um deles está parado, o TaskScheduler coloca-o para trabalhar. * Não precisamos mais nos preocupar em dividir tarefas para cada thread, pois ele faz isto. Quando usamos a Factory, propriedade estática * da classe Task, utilizamos o TaskScheduler default que o .NET nos fornece. */ var contasTarefa = contas.Select(conta => { // Task ("tarefa" em inglês). Ele possui uma propriedade estática, Factory, que constrói tarefas. Nossa nova tarefa é constituída //por outra expressão lambda, a qual não recebe nenhum parâmetro, em que faremos a consolidação desta conta. return(Task.Factory.StartNew(() => { var resultado = r_Servico.ConsolidarMovimentacao(conta); resultados.Add(resultado); })); }).ToArray(); /* * To Array * Relembremos que Select é uma função do LINQ, que age de forma mais "preguiçosa" possível. Neste momento, na execução da próxima * linha: var fim = DateTime.Now;. Nenhuma tarefa foi criada, pois o LINQ executa queries somente quando necessário. Se não usamos * a variável contasTarefas, o código que vem a seguir não é executado. Vamos forçar todas as tarefas a serem criadas, gerando um * array (.ToArray();) e obrigando o LINQ a executá-las: */ /* WaitAll: Nao faça nada até que as todas as threads tenham sido executadas: * Por isso, criaremos um laço de repetição while para verificar se a thread IsAlive... Não nos preocupamos mais com threads, * tampouco com esta propriedade. Faremos isto de um jeito diferente: o Task possui um método estático chamado WaitAll que não faz * nada até que todas as outras tarefas sejam finalizadas. Este método recebe uma lista de tarefas como parâmetro, travando a * execução deste até que todas as tarefas terminem. */ //Task.WaitAll(contasTarefa); /* * No momento em que se alcança o código Task.WaitAll(contasTarefas), a aplicação é pausada, e as linhas seguintes - de finalização e atualização da tela * - só serão executadas quando terminarmos todas as tarefas existentes. Verificaremos seu funcionamento apertando "Start" mais uma vez e acompanhando * o uso das CPUs pelo Gerenciador de Tarefas.*/ //com o whenAll conseguimos encadear outras tarefas. Task.WhenAll(contasTarefa) .ContinueWith(task => { //Parametro task:dentro do corpo da função temos disponível a task que originou a execução.. Ou seja, a task será a tarefa que espera todas as outras (Task.WhenAll()) //Termino do processamento var fim = DateTime.Now; AtualizarView(resultados, fim - inicio); //Não podemos alterar um objeto da interface gráfica a partir de outras Threads por isso eu preciso do contexto da thread UI(princiual) //que esta no objecto taskSchedulerUI; BtnProcessar.IsEnabled = true; }, taskSchedulerUI); this.Cursor = Cursors.Arrow; }