VB .NET - Apresentando o conceito de Task |
Neste artigo vou apresentar o conceito de Task disponível a partir da versão 4.0 da plataforma .NET usando a linguagem VB .NET. |
A partir da versão 4.0 da plataforma .NET temos acesso ao namespace System.Threading.Tasks, o qual contém classes que permitem abstrair a funcionalidade de threading onde, na verdade, por trás dos panos, uma ThreadPool é usada.
Uma tarefa (ou task) representa uma unidade de trabalho que deverá ser realizada. Esta unidade de trabalho, que é uma operação assíncrona, pode rodar em uma thread separada e é também possível iniciar uma task de forma sincronizada a qual resulta em uma espera pela thread chamada. Com tarefas, você tem uma camada de abstração mas também um bom controle sobre as threads relacionadas.
As tarefas (tasks) permitem muito mais flexibilidade na organização do trabalho que você precisa fazer. Por exemplo, você pode definir continuar o trabalho, que deve ser feito depois que uma tarefa esteja completa. Isso pode diferenciar se um tarefa foi executada com sucesso ou não. Você também pode organizar as tarefas em hierarquia onde uma tarefa pai pode criar novas tarefas filhas que pode criar dependências e assim o cancelamento da tarefa pai também cancela suas tarefas filhas.
Iniciando Task
O classe Task representa uma única operação que não retorna um valor e que geralmente é executado de maneira assíncrona. Ela possui 5 sobrecarga para seus construtores.
O construtor mais usado é : Task(Action) que inicializa uma nova task com uma ação especificada.
As principais propriedades da classe Task são:
Nome | Descrição |
---|---|
AsyncState |
|
CompletedTask |
|
CreationOptions |
|
CurrentId |
|
Exception |
Se a Task foi concluída com êxito ou não ainda acionou todas as exceções, retornará null. |
Factory |
|
Id |
|
IsCanceled |
|
IsCompleted |
|
IsFaulted |
|
Status |
|
Os métodos mais importantes da classe Task são:
Nome | Descrição |
---|---|
ContinueWith() | Cria uma continuação que recebe informações de estado fornecido pelo chamador e é executada quando a Task de destino é concluída. |
Delay(int32) |
Cria
uma tarefa que é concluída após um tempo
|
Run(Action) |
Enfileira
o trabalho especificado para ser executado no ThreadPool e retorna
um identificador de tarefa para esse trabalho
|
Start() |
Inicia
a Task,
agendando-a para execução no
TaskScheduler atual
|
Wait() |
Espera
até que a
Task conclua
|
WaitAll() | Aguarda todos objetos Task fornecidos concluir a execução |
WaitAny() |
Aguarda
qualquer um dos objetos Task fornecidos concluir a execução.
|
WhenAll() |
Cria
uma tarefa que será concluída quando todos os
objetos
Task em uma coleção enumerável foram concluídos.
|
WhenAny |
Cria
uma tarefa que será concluída quando qualquer tarefa fornecida foi
concluída.
|
Nota: Apresentei aqui apenas um breve resumo. Para detalhes confira : https://msdn.microsoft.com/pt-br/library/system.threading.tasks.task%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1
Vamos agora mostrar alguns exemplos de utilização da classe Task.
Recursos usados:
Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.
Criando a solução no VS Community
Abra o VS Community 2015 e clique em New Project;
Selecione a linguagem Visual Basic e o template Console Application;
Informe o nome VBNET_Tasks e clique no botão OK;
1 - Iniciando Tasks
Para iniciar uma tarefa, você pode usar a classe TaskFactory ou o construtor da classe Task e o método Start().
O construtor Task lhe dá mais flexibilidade na criação da tarefa. Ao iniciar uma tarefa, uma instância da classe Task pode ser criada e o código que deve ser executado pode ser atribuído com uma Action ou delegate Action(object) tanto sem parâmetro como com um parâmetro object. Isto é muito semelhante ao que você já viu na classe Thread.
Instâncias de tarefas podem ser criadas de várias maneiras. A abordagem mais comum é utilizar o tipo de propriedade Factory do tipo Task para recuperar uma instância TaskFactory que pode ser usada para criar tarefas para vários propósitos.
Por exemplo, para criar uma tarefa que executa uma ação, o método Factory.StartNew pode ser usado:
Module Module1
Sub Main()
Dim t = Task.Factory.StartNew(Sub() FazerAlgo())
Console.ReadKey()
End Sub
Private Sub FazerAlgo()
Console.WriteLine("executando uma tarefa => FazerAlgo() (task)")
End Sub
End Module
|
Existem maneiras diferentes para iniciar uma nova tarefa.
A primeira maneira é instanciando uma classe TaskFactory, onde o método MetodoTarefa é passado para o método StartNew(), e a tarefa é iniciada imediatamente:
Sub Main() ' usando factory task Dim tf As New TaskFactory() Dim t1 As Task = tf.StartNew(Sub() FazerAlgo()) End Sub |
O método StartNew cria e inicia a Task.
A segunda abordagem usa o construtor da classe de Task. Quando o objeto Task é instanciado, a tarefa não será executada imediatamente. Em vez disso, a ela é dado o status Created. A tarefa é, então iniciada pela chamada do método Start() da classe Task.
Sub Main() ' usando o construtor Task Dim tf3 As New Task(Sub() FazerAlgo()) tf3.Start() Console.ReadKey() End Sub |
Com a classe de Task, ao invés de invocar o método Start(), você pode invocar o método RunSynchronously().
Desta forma, a tarefa é iniciada também, mas ela está sendo executada na thread atual do chamador, o chamador precisa esperar até que a tarefa termine. Por padrão, a tarefa é executada de forma assíncrona.
A classe Task também fornece construtores que inicializam a tarefa, mas que não a agendam para execução. Por razões de desempenho, o método StartNew da classe TaskFactory deve ser o mecanismo preferido para criação e programação de tarefas, mas, para situações em que a criação e programação devem ser separadas, os construtores podem ser usados, e o método Start() da tarefa pode então ser utilizado para programar a tarefa para execução em um momento posterior.
Para as operações que retornam valores a classe Task(Of Resultado> deve ser usada.
Module Module1
Sub Main()
Dim t As Task = Task.Run(Sub()
'Apenas um loop
Dim ctr As Integer = 0
For ctr = 0 To 999999
Next
Console.WriteLine("Finalizado {0} iterações do loop", ctr)
End Sub)
'espera a tarefa completar a execução
t.Wait()
Console.WriteLine("Operação concluída...")
Console.ReadKey()
End Sub
End Module
|
Continuando Tarefas
Usando a classe Tasks você pode especificar que, depois que uma tarefa for concluída outra tarefa específica deve começar a ser executada; por exemplo, uma nova tarefa que usa um resultado da anterior ou que deve fazer uma limpeza se a tarefa anterior falhou. Considerando que o manipulador tarefa ou não tem parâmetro ou tem um parâmetro object, o manipulador de continuação tem um parâmetro do tipo Task. Aqui, você pode acessar informações sobre a tarefa de origem.
Na programação assíncrona, é muito comum para uma operação assíncrona, na conclusão, invocar uma segunda operação e passar os dados para ela.
Tradicionalmente, isto tem sido feito por meio de métodos de retorno. Na biblioteca Task Parallel , a mesma funcionalidade é fornecida por tarefas de continuação.
Uma tarefa de continuação (também conhecida como uma continuação) é uma tarefa assíncrona que é invocada por outra tarefa, o que é conhecido como a antecedente, quando a antecedente termina.
As Continuações são relativamente fáceis de utilizar, mas são, contudo, muito eficientes e flexíveis. Por exemplo, você pode:
Podemos criar continuações usando o método Task.ContinueWith. O exemplo a seguir mostra o padrão básico, (por motivos de clareza, o tratamento de exceção é omitido).
Module Module1
Sub Main()
' 1-) A tarefa antecedente.
' Pode tambem ser criada com Task.Factory.StartNew.
Dim tarefa1 As New Task(Of DayOfWeek)(Function() DateTime.Today.DayOfWeek)
' 2-) A continuacao.
' Seu delegate toma a tarefa antecedente como um argumento e pode retornar um tipo diferente
Dim continuacao As Task(Of String) = tarefa1.ContinueWith(Function(antecedente)
Return [String].Format("Hoje é {0}.", antecedente.Result)
End Function)
' Iniciar a antecedente
tarefa1.Start()
' Usar o resultado da continuacao
Console.WriteLine(continuacao.Result)
Console.ReadKey()
End Sub
End Module
|
Também é possível criar uma continuação multitarefa que será executada quando qualquer uma ou todas as tarefas de um array de tarefas tiverem sido completadas, como mostrado a seguir:
Module Module1
Sub Main()
'Cria um array de tarefas
Dim tarefas As Task(Of Integer)() = New Task(Of Integer)(1) {}
'define a primeira tarefa para retornar 450
tarefas(0) = New Task(Of Integer)(Function()
' faz alguma coisa...
Return 450
End Function)
'define a segunda tarefa para retornar 800
tarefas(1) = New Task(Of Integer)(Function()
' faz alguma coisa...
Return 800
End Function)
'defina a continuacao usando o método ContinueWhenAll
'obtendo os resultados das tarefas e retornando a soma
Dim continuacao = Task.Factory.ContinueWhenAll(tarefas, Sub(antecedentes)
Dim resposta As Integer = tarefas(0).Result + tarefas(1).Result
Console.WriteLine("A resposta é {0}", resposta)
End Sub)
'inicia a tarefa agendando a execução tarefas(0).Start() tarefas(1).Start() 'aguarda a tarefa ser concluída continuacao.Wait() Console.WriteLine("Processamento concluído...") Console.ReadKey() End Sub End Module
|
O método ContinueWhenAll cria uma tarefa de continuação(executa o delegate continuationAction) que inicia quando o conjunto de tarefas especificadas foram concluídas, independente de seu status de conclusão.
Uma continuação é criada no estado WaitingForActivation e, portanto, só pode ser iniciada por sua tarefa antecedente. Chamar Task.Start em uma continuação no código do usuário levanta uma exceção System.InvalidOperationException.
A continuação é por si só uma tarefa e não bloqueia a thread na qual ela é iniciada. Use o método Wait para bloquear até a tarefa da continuação terminar.
A classe Task da suporte a cancelamento cooperativo e é totalmente integrada com a classe System.Threading.CancellationTokenSource e com a classe System.Threading.CancellationToken, que são novos no Framework 4. NET.
Muitos dos construtores da classe System.Threading.Tasks.Task tomam um CancellationToken como parâmetro de entrada e muitas das sobrecargas StartNew e Run também possuem um CancellationToken.
Aguarde em breve mais artigos abordando os recursos do conjunto de APIs da Task Parallel Library (TPL).
Pegue o projeto completo aqui: VBNET_Tasks.zip
E os que são de Cristo crucificaram a
carne com as suas paixões e concupiscências.
Gálatas 5:24
Veja os
Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique
e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ? |
Gostou ? Compartilhe no Facebook Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#