| Já está disponível a MSDN Magazine de Abril de 2010. Nesta edição é possível ler diversos artigos como: Entre outros artigos! | |
Destacar obviamente o artigo What’s New in Visual Basic 2010 que fala sobre as principais novidades do Visual Basic 2010, como Implicit Line Continuation, Statement Lambdas, Auto-Implemented Properties, Collection Initializers, Array Literals, Dynamic Language Runtime (DLR), etc (que já foram na maioria também referidas neste blog), e ainda a Coevolution entre o Visual Basic e o C#.
Um artigo também muito interessante de Better Coding with Visual Studio 2010 que refere algumas novidades do Visual Studio 2010, nomeadamente, Visual Studio IDE Improvements, Support for Parallel Programming, Web Updates, MVC Integration, SharePoint Integration, etc.
Nos artigos anteriores sobre a Task Parallel Library (TPL) foram referidos os métodos Parallel.For e Parallel.ForEach que servem essencialmente para criar ciclos que podem correr em paralelo. Este método, o Parallel.Invoke, serve para executar processos que decorrem eventualmente em paralelo.
Quando os processos são invocados, são separados nos diversos núcleos do processador e o código só avança quando todos tiverem terminado.
Eis um exemplo do funcionamento:
Imports System.Threading
Imports System.Threading.Tasks
Module Module1
Private Sub task1()
For x As Integer = 0 To 50
Console.WriteLine("Task1 - {0}", x.ToString())
System.Threading.Thread.SpinWait(50000000)
Next
End Sub
Private Sub task2()
For x As Integer = 0 To 50
Console.WriteLine("Task2 - {0}", x.ToString())
System.Threading.Thread.SpinWait(50000000)
Next
End Sub
Sub Main()
' Chama as diversas acções (incluindo uma Lambda)
Dim actions() As Action = {AddressOf task1, AddressOf task2,
Sub()
' Usando uma Lambda Expression
For x As Integer = 0 To 50
Console.WriteLine("Task3 - {0}", x.ToString())
System.Threading.Thread.SpinWait(50000000)
Next
End Sub}
Parallel.Invoke(actions)
Console.WriteLine("Acções completas!")
End Sub
End Module
Executando o mesmo, mas sequencialmente (onde o tempo de execução é significativamente superior):
Imports System.Threading
Imports System.Threading.Tasks
Module Module1
Private Sub task1()
For x As Integer = 0 To 50
Console.WriteLine("Task1 - {0}", x.ToString())
System.Threading.Thread.SpinWait(50000000)
Next
End Sub
Private Sub task2()
For x As Integer = 0 To 50
Console.WriteLine("Task2 - {0}", x.ToString())
System.Threading.Thread.SpinWait(50000000)
Next
End Sub
Sub Main()
task1()
task2()
For x As Integer = 0 To 50
Console.WriteLine("Task3 - {0}", x.ToString())
System.Threading.Thread.SpinWait(50000000)
Next
End Sub
End Module
E é o terceiro e último evento da classe Parallel. Como se pode ver nos exemplos apresentados(For, ForEach e Invoke), são muito simples de utilizar e vai de certeza ajudar a melhorar o desempenho das aplicações.
Este método executa um ciclo semelhante à instrução For Each, mas que possibilita a execução em paralelo. É muito semelhante ao exemplo do artigo anterior, mas difere do Parallel.For() pois é usado quando os dados são colecções ou arrays.
Eis um exemplo da sua implementação/utilização:
Imports System.Threading
Imports System.Threading.Tasks
Module Module1
Sub Main()
Dim result1, result2 As Long
Dim values = Enumerable.Range(0, 49)
Dim sw As New Stopwatch
sw.Start()
' ------------------------------------------------
' Ciclo For Each
' ------------------------------------------------
For Each value As Integer In values
Console.WriteLine("Value:{0} GUI:{1}", value.ToString(), Guid.NewGuid())
Thread.SpinWait(50000000)
Next
result1 = sw.ElapsedMilliseconds
sw.Restart() ' <- novo método no Visual Studio 2010
' ------------------------------------------------
' Ciclo Parallel.ForEach
' ------------------------------------------------
Parallel.ForEach(values, Sub(value)
Console.WriteLine("Value:{0} GUI:{1}",
value.ToString(),
Guid.NewGuid())
Thread.SpinWait(50000000)
End Sub)
result2 = sw.ElapsedMilliseconds
sw.Stop()
Console.WriteLine("Tempo de execução 'For Each' {0} ms", result1)
Console.WriteLine("Tempo de execução 'Parallel.ForEach' {0} ms", result2)
Console.ReadKey(True)
End Sub
End Module
E os resultados são uma vez mais significativos:

É mais um ciclo disponível da Task Parallel Library (TPL) – Parallel Extensions, que quando bem aplicado pode melhorar bastante o desempenho da aplicação.
Data parallelism refere-se a situações em que a mesma operação é realizada simultaneamente (ou seja em paralelo) em elementos de uma colecção ou array. A classe System.Threading.Tasks.Parallel, do namespace System.Threading.Tasks, fornece um conjunto de métodos que permitem a execução de ciclos. Com a utilização do Parallel.For, Parallel.ForEach e Parallel.Invoke, incluindo inúmeros overloads disponíveis, é possível melhorar o desempenho das aplicações.
O método Parallel.For executa um ciclo que pode correr em paralelo. O sintaxe é o seguinte: Parallel.For(Int32, Int32, Action(Of Int32))
Executando um ciclo simples ou “normal”:
Dim sw As New Stopwatch()
sw.Start()
' Executa o método For ... Next
For x As Integer = 0 To 500
Console.WriteLine("Thread ID={0} - x={1}",
Thread.CurrentThread.ManagedThreadId, x)
Thread.Sleep(100)
Next x
Console.WriteLine("Tempo de execução: {0} ms", sw.ElapsedMilliseconds)
sw.Stop()
Como é possível ver nos seguintes resultados, o tempo de execução é longo, e o valor da variável x que é mostrado é continuo. A thread é também sempre a mesma (neste caso 9).

Para realizarmos o mesmo ciclo, mas desta vez recorrendo às Parallel Extensions, e melhorando desta forma o desempenho, podemos usar o método Parallel.For. Neste exemplo é usado Lambda para mostrar os resultados:
Dim sw As New Stopwatch()
sw.Start()
' Executa o método Parallel.For()
Parallel.For(0, 500, Sub(x)
Console.WriteLine("Thread ID={0} - x={1}",
Thread.CurrentThread.ManagedThreadId, x)
Thread.Sleep(100)
End Sub)
Console.WriteLine("Tempo de execução: {0} ms", sw.ElapsedMilliseconds)
sw.Stop()
Como é possível nos seguintes resultado, o tempo de execução é inferior, sendo usadas diversas threads, que são distribuídas e executadas nos diversos núcleos do processador. Isto justifica também porque o valor de x não é mostrado de forma continua.

Os resultados falam por si, ma é importante lembrar, que num exemplo simples sem que existam tarefas complexas (que possam demorar algum tempo a executar), a utilização dos métodos Parallel.For ou Parallel.ForEach é mais lento do que um ciclo simples (For … Next ou For Each … Next). Isto porque em cada ciclo é criada um Delegate (System.Action) que irá ser chamado e isso irá aumentar o tempo de execução.
É por isto muito importante definir bem onde utilizar, desenhar a aplicação de modo a poder incluir a utilização de Parallel Extensions, neste caso as Task Parallel Library (TPL), e testar sempre (analisando os resultados)!