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 async void Aula03_UsandoAsyncAwait() { BtnProcessar.IsEnabled = false; var contas = r_Repositorio.GetContaClientes(); AtualizarView(new List <string>(), TimeSpan.Zero); var inicio = DateTime.Now; var resultado = await ConsolidarContas(contas); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; #region Metodo de fazer sem o async await /*Metodo sem async await*/ //ConsolidarContas(contas) // .ContinueWith(task => //ContinueWith será execuldado somente quando todas as tarefas anteriores forem completadas, // { //O ContinueWith ecebe como parametro uma Task (Tarefa), que é justamente a que originou o metodo // var resultado = task.Result; // var fim = DateTime.Now; // AtualizarView(resultado, fim - inicio); // }, _taskSchedulerUI) // .ContinueWith(task => // { // BtnProcessar.IsEnabled = true; // }, _taskSchedulerUI); #endregion }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; // Atribuindo valor ao token de cancelamento _cts = new CancellationTokenSource(); var contas = r_Repositorio.GetContaClientes(); PgsProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; BtnCancelar.IsEnabled = true; // ByteBankProgress classe criada pela gente, que faz o mesmo papal que a classe Progress do .NET //var byteBanckProgress = new Utils.ByteBankProgress<string>(str => //{ // PgsProgresso.Value++; //}); // Mesma implementação que acima, porem utilizando classe ja pronto do .NET var progress = new Progress <string>(str => { PgsProgresso.Value++; // Ação que sera executada para atualizar barra de progresso dentro do ConsolidarContas() }); try { // Utilizando async await var resultado = await ConsolidarContas(contas, progress, _cts.Token); // Codigo abaixo só sera executo assim que as Tasks forem concluidas var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); } catch (Exception) { TxtTempo.Text = "Operação cancelada pelo usuario"; PgsProgresso.Value = 0; } finally { BtnCancelar.IsEnabled = false; BtnProcessar.IsEnabled = true; } }
private void BtnProcessar_Click(object sender, RoutedEventArgs e) { this.Cursor = Cursors.Wait; 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; ConsolidarContas(contas) .ContinueWith(task => { var fim = DateTime.Now; var resultado = task.Result; //A propriedade Rseulta armaza o valor de retorno da nossa task retornada no metodo ConsolidarContas AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; }, taskSchedulerUI); //estamos encadeando outras task que é a UI (principal) this.Cursor = Cursors.Arrow; }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { try { BtnProcessar.IsEnabled = false; _ctr = new CancellationTokenSource(); var contas = r_Repositorio.GetContaClientes(); PgsProgresso.Maximum = contas.Count(); LimparView(); BtnCancelar.IsEnabled = true; var inicio = DateTime.Now; var progresso = new Progress <string>(str => PgsProgresso.Value++); var resultado = await ConsolidarContas(contas, progresso, _ctr.Token); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); } catch (OperationCanceledException) { TxtTempo.Text = "Operação cancelada"; } finally { BtnProcessar.IsEnabled = true; BtnCancelar.IsEnabled = false; } }
private void BtnProcessar_Click(object sender, RoutedEventArgs e) { var contas = r_Repositorio.GetContaClientes(); // Irá retornar o gerenciador de tarefas que está atuando no momento, no caso na thread principal var TaskScheduler_UI = TaskScheduler.FromCurrentSynchronizationContext(); BtnProcessar.IsEnabled = false; AtualizarView(new List <string>(), TimeSpan.Zero); var inicio = DateTime.Now; // Quando a tarefa que consilida todas as contas for concluida novas tarefas serão criadas para seguir o processo corretamente ConsolidarContas(contas) .ContinueWith(task => // Tarefa 1 => (Após Consolidar as Contas) { var fim = DateTime.Now; // Irá recuperar o resultado da tarefa que originou essa nova tarefa atual, // no caso o retorno da função ConsolidarContas(contas) var resultado = task.Result; // E tmb irá atualizar a view mostrando o desempenho obtido AtualizarView(resultado, fim - inicio); }, TaskScheduler_UI) // Especificando que as tarefas precisam ser executas no gerenciador de tasks da Thread Principal .ContinueWith(task => // Tarefa 2 => (Após o conclusão da Tarefa 1) { BtnProcessar.IsEnabled = true; }, TaskScheduler_UI); // Task.WaitAll(contasTarefas); => Não segue o processo da Thread atual até que todas as tasks do array de tasks sejam concluidos }
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 void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnCancelar.IsEnabled = true; pgsProgresso.Visibility = Visibility.Visible; BtnProcessar.IsEnabled = false; var btnContent = BtnProcessar.Content; BtnProcessar.Content = "Processando..."; AtualizarView(new List <string>(), TimeSpan.Zero); _cts = new CancellationTokenSource(); var contas = r_Repositorio.GetContaClientes(); pgsProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; var progress = new ByteBankProgress <string>(str => pgsProgresso.Value++); try { var resultado = await ConsolidarContas(contas, progress, _cts.Token); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); } catch (OperationCanceledException) { TxtTempo.Text = "Operação cancelada pelo usuário"; } finally { BtnProcessar.IsEnabled = true; BtnProcessar.Content = btnContent; BtnCancelar.IsEnabled = false; } }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { //TaskScheduler UITask = TaskScheduler.FromCurrentSynchronizationContext(); BtnProcessar.IsEnabled = false; IEnumerable <ContaCliente> contas = r_Repositorio.GetContaClientes(); //List<string> resultado = new List<string>(); AtualizarView(new List <string>(), TimeSpan.Zero); DateTime inicio = DateTime.Now; string[] resultado = await ConsolidarContas(contas); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; // EXAMPLE WITHOUT AWAIT USING FUNCTIONS //ConsolidarContas(contas) // .ContinueWith(task => // { // var fim = DateTime.Now; // var resultado = task.Result; // AtualizarView(resultado, fim - inicio); // BtnProcessar.IsEnabled = true; // //}, UITask) // //.ContinueWith(task => // //{ // // BtnProcessar.IsEnabled = true; // }, UITask); // END OF EXAMPLE // EXAMPLE WITHOUT AWAIT WITHOUT FUNCTIONS //Task[] contasTarefas = contas.Select(conta => //{ // return Task.Factory.StartNew(() => // { // string resultadoConta = r_Servico.ConsolidarMovimentacao(conta); // resultado.Add(resultadoConta); // }); //}).ToArray(); //Task.WhenAll(contasTarefas) // .ContinueWith(task => // { // DateTime fim = DateTime.Now; // AtualizarView(resultado, fim - inicio); // }, UITask) // .ContinueWith(task => // { // BtnProcessar.IsEnabled = true; // }, UITask); // END OF EXAMPLE }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; this.BtnCancelar.IsEnabled = true; _cts = new CancellationTokenSource(); //Obtem as contas do usuarios var contas = r_Repositorio.GetContaClientes(); this.PgsProgresso.Maximum = contas.Count(); //Limpar a tela. LimparView(); //Inicio do processamento var inicio = DateTime.Now; var progress = new Progress <String>(str => PgsProgresso.Value++); // var byteBankProgress = new ByteBankProgress<String>(str => // PgsProgresso.Value++); //await //O recurso se chama AsyncAwait e não é à toa. A primeira palavra chave é o async, e a segunda é o await. //Podemos usá-lo para consolidar as contas, pois trata-se de uma task, a qual sempre pode ser aguardada. // Daqui em diante, voltamos a executar no contexto da thread inicial. Ao utilizarmos ConsolidarContas() //temos uma tarefa que retorna uma lista de string, e nossa preocupação não é com a tarefa, e sim com seu //resultado, a lista de string.Usando o await, podemos armazenar apenas o resultado desta tarefa em uma variável. //Vamos também comentar a linha var resultado = task.Result; para não haver conflito entre nomes. try { var fim = DateTime.Now; var resultado = await ConsolidarContas(contas, progress, _cts.Token); AtualizarView(resultado, fim - inicio); } catch (OperationCanceledException) { this.TxtTempo.Text = "Operação cancelada pelo usuario"; } finally { this.BtnProcessar.IsEnabled = true; this.BtnCancelar.IsEnabled = false; } /* * Nosso resultado não é uma task de lista de string como está definido em nossa função. O resultado é apenas uma lista de * string pois aqui, na verdade, é como se estivessemos dentro de um ContinueWith(). Mas todo o ornamento de criar-se uma * task, entre outros, se dá pelo compilador, deixando o código muito menos indentado, com menos níveis e uma "cara mais natural", * com que estamos acostumados. * * Ao executarmos no contexto original, não precisamos mais nos preocupar em guardar o contexto no início da função, * porque o compilador já fará isto. Não precisamos nos preocupar com os encadeamentos referentes ao fim, atualização de * view e clique do botão. Sendo assim, vamos removê-los de ConsolidarContas(), deletando-se este também: */ }
private void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; AtualizarView(new List <string>(), TimeSpan.Zero); var contas = r_Repositorio.GetContaClientes(); var inicio = DateTime.Now; /// /// Diferentes formas de processar //ProcessarContas_Thread(contas, inicio); ProcessarContas_ContinueWith(contas, inicio); //ProcessarContas(contas, inicio); }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; var contas = r_Repositorio.GetContaClientes(); AtualizarView(new List <string>(), TimeSpan.Zero); var inicio = DateTime.Now; var resultado = await ConsolidaContas(contas); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; var contas = r_Repositorio.GetContaClientes(); PgsProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; var resultado = await ConsolidarContas(contas, new Progress <string>(str => PgsProgresso.Value++)); AtualizarView(resultado, DateTime.Now - inicio); BtnProcessar.IsEnabled = !BtnProcessar.IsEnabled; }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { // Pegando o contexto da Thread principal var taskSchedulerUI = TaskScheduler.FromCurrentSynchronizationContext(); BtnProcessar.IsEnabled = false; _cts = new CancellationTokenSource(); var contas = r_Repositorio.GetContaClientes(); PgsProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; BtnCancelar.IsEnabled = true; var progress = new Progress <String>(str => PgsProgresso.Value++); // Essa classe que foi criada implementa praticamente a mesma coisa que o método Progress acima // porém dessa forma eu consigo customizar se eu quiser // var byteBankProgress = new ByteBankProgress<String>(str => // PgsProgresso.Value++); try { var resultado = await ConsolidarContas(contas, progress, _cts.Token); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); } catch (OperationCanceledException) { TxtTempo.Text = "Operação cancelada pelo usuário"; } finally { BtnProcessar.IsEnabled = true; BtnCancelar.IsEnabled = false; } }
// Método que será executado de forma Assíncrona private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { var contas = r_Repositorio.GetContaClientes(); BtnProcessar.IsEnabled = false; AtualizarView(new List <string>(), TimeSpan.Zero); var inicio = DateTime.Now; // A Thread principal só irá seguir o seu processo se a tarefa de consolidar as contas for concluída // Usando await além de ter essa espera, o resultado da task pode ser atrubuida a uma variavel, ou seja o resultado da tarefa var resultado = await ConsolidarContas(contas); // Após a task for concluída o fluxo irá seguir normalmente var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { var contas = r_Repositorio.GetContaClientes(); var taskSchedulerUI = TaskScheduler.FromCurrentSynchronizationContext(); BtnProcessar.IsEnabled = false; _cts = new CancellationTokenSource(); PgsProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; BtnCancelar.IsEnabled = true; var byteBankProgress = new ByteBankProgress <String>(str => PgsProgresso.Value++); Progress <string> progress = new Progress <String>(str => PgsProgresso.Value++); try { var resultado = await ConsolidarContas(contas, progress, _cts.Token); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); } catch (OperationCanceledException) { TxtTempo.Text = "Operação cancelada pelo usuário"; } finally { BtnProcessar.IsEnabled = true; BtnCancelar.IsEnabled = false; } BtnProcessar.IsEnabled = true; }
private async void BtnProcessar_Click(object sender, EventArgs e) { _cts = new CancellationTokenSource(); BtnProcessar.Enabled = false; BtnCancelar.Enabled = true; var contas = r_Repository.GetContaClientes(); PsgProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; var progress = new Progress <string>(srt => { PsgProgresso.Value++; ListResultados.Items.Add(srt); }); try { var resultado = await ConsolidarContas(contas, progress, _cts.Token); var fim = DateTime.Now; AtualizarView(resultado.ToList(), fim - inicio); } catch (OperationCanceledException) { TxtTempo.Text = "Operação cancelada pelo usuário!"; } finally { BtnProcessar.Enabled = true; BtnCancelar.Enabled = false; } }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; var contas = r_Repositorio.GetContaClientes(); PgsProgresso.Maximum = contas.Count(); LimparView(); var inicio = DateTime.Now; var progress = new Progress <String>(str => PgsProgresso.Value++); //var byteBankProgress = new ByteBankProgress<String>(str => // PgsProgresso.Value++); var resultado = await ConsolidarContas(contas, progress); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; }
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); }
private async void BtnProcessar_Click(object sender, RoutedEventArgs e) { BtnProcessar.IsEnabled = false; _cts = new CancellationTokenSource(); var contas = r_Repositorio.GetContaClientes(); PgsProgresso.Maximum = contas.Count(); //var resultado = new List<string>(); // AtualizarView(new List<string>(), TimeSpan.Zero); LimparView(); var inicio = DateTime.Now; BtnCancelar.IsEnabled = true; var progress = new Progress <String>(str => PgsProgresso.Value++); //var byteBankProgress = new ByteBankProgress<string>(str => PgsProgresso.Value++); try { var resultado = await ConsolidarContas(contas, progress, _cts.Token); var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); BtnProcessar.IsEnabled = true; } catch (OperationCanceledException) { TxtTempo.Text = "Operação Cancelada pelo usúario"; } finally { BtnProcessar.IsEnabled = true; BtnCancelar.IsEnabled = false; } #region old way // var taskSchedulerUI = TaskScheduler.FromCurrentSynchronizationContext(); //var contasTarefas = contas.Select(conta => //{ // return Task.Factory.StartNew(() => // { // var resultadoConta = r_Servico.ConsolidarMovimentacao(conta); // resultado.Add(resultadoConta); // }); //}).ToArray(); //ConsolidarContas(contas).ContinueWith(task => { // var fim = DateTime.Now; // var resultado = task.Result; // AtualizarView(resultado, fim - inicio); // }, taskSchedulerUI) // .ContinueWith(task => // { // BtnProcessar.IsEnabled = true; // }, taskSchedulerUI); #endregion }
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); }
public IEnumerable <ContaCliente> GetContaClientes() { return(contaClienteRepository.GetContaClientes()); }
/// 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; }
/// 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; //Obtem as contas do usuarios var contas = r_Repositorio.GetContaClientes(); // a porção para cada thread processar var contasQuantidadePorThread = contas.Count() / 4; //vamos dividir o resultado da thread //Take(), que recebe, por parâmetro, um número inteiro que representa os n primeiros elementos a serem armazenados var contas_parte1 = contas.Take(contasQuantidadePorThread); //Skip(), que recebe por parâmetro um número inteiro que representa os n primeiros elementos a serem pulados da lista. var contas_parte2 = contas.Skip(contasQuantidadePorThread).Take(contasQuantidadePorThread); var contas_parte3 = contas.Skip(contasQuantidadePorThread * 2).Take(contasQuantidadePorThread); var contas_parte4 = contas.Skip(contasQuantidadePorThread * 3); //Atualiza a lista AtualizarView(new List <string>(), TimeSpan.Zero); //Inicio do processamento var inicio = DateTime.Now; //Thread:"linha de execução", que na realidade é a tradução de "thread", termo técnico bastante comum na computação quando falamos sobre Paralelismo. Thread thread_parte1 = new Thread(() => { ConsolidarMovimentacao(contas_parte1); }); Thread thread_parte2 = new Thread(() => { ConsolidarMovimentacao(contas_parte2); }); Thread thread_parte3 = new Thread(() => { ConsolidarMovimentacao(contas_parte3); }); Thread thread_parte4 = new Thread(() => { ConsolidarMovimentacao(contas_parte4); }); //Aqui estou executando de fato as threads. thread_parte1.Start(); thread_parte2.Start(); thread_parte3.Start(); thread_parte4.Start(); //O compilador nao vai esperar o processador processasr as thread acima. Precisamo pedir //gentilemente para ele esperar. Como fazemos isso? com a proprieadde Alive: //================================================================================================ // IsAlive --------------------------------------------------------------------------------------- //================================================================================================ // A classe Thread possui uma propriedade denominada IsAlive, que retorna "verdadeiro" quando ela está em execução, //e "falso" ao fim de seu processamento. Vamos utilizá-la para ficarmos presos a este método até que as threads terminem. while (thread_parte1.IsAlive || thread_parte2.IsAlive || thread_parte3.IsAlive || thread_parte4.IsAlive) { //Aquele comentário que colocamos, //Não vou fazer nada, não é totalmente verdadeiro. Momento após momento, //a app verifica o IsAlive da thread_parte1 e, depois, da thread_parte2. É um trabalho, esta execução incessante //do laço de repetição, causando uso de CPU. // Entre uma pergunta e outra, podemos, de fato, não fazer nada. Para isto, ou seja, para não usarmos a CPU, //pode -se usar um método estático da classe Thread chamado Sleep: //Não vou fazer nada Thread.Sleep(250); //====================================== //Sleep ------------------------------- //====================================== //O Sleep é um método que, literalmente, coloca a Thread para dormir. Ela recebe por parâmetro um número inteiro //que representa o número de milisegundos durante os quais a Thread ficará sem fazer nada. //O processamento foi finalizado... Se antes demorava-se mais de 40s, a linha de código que acabamos de acrescentar //para fazer a Thread principal parar de ficar perguntando incessantemente se as threads estão trabalhando, nos fez diminuir //este tempo consideravelmente, passando a levar 30s para consolidar a informação de todos os clientes de desenvolvimento. } //Termino do processamento var fim = DateTime.Now; AtualizarView(resultado, fim - inicio); this.Cursor = Cursors.Arrow; }