Ultimamente, os processadores de computadores e notebooks estão sendo fabricados com mais de um núcleo. Isso requer um olhar especial por quem desenvolve software e o deseja fazer com qualidade, por isso, vamos falar sobre Programação Paralela.

Você sabe o que é isto? Muita gente confunde programação paralela com programação concorrente. Concorrência é quando um servidor atende a vários clientes escalando um determinado tempo para atender cada um, já o Paralelismo é quando vários servidores atendem vários clientes ao mesmo tempo, reduzindo o tempo de resposta para os clientes.

Com isso, há um ganho em performance, pois assim, desafoga o núcleo do processador e diminui o consumo de energia do computador, visto que isso é uma grande preocupação hoje em dia com o que é chamado de TI Verde.

Mas, escrever programas que utilizem paralelismo é um pouco diferente de escrever de maneira seqüencial, como estamos mais acostumados a fazer. Temos que escolher que partes do programa utilizarão código que serão executados em paralelo. Outras preocupações que devemos ter são quando as informações tiverem que ser processadas em uma determinada ordem ou definir até que nível de paralelismo será utilizado.

Visando facilitar essas decisões que o desenvolvedor terá que tomar, irei mostrar aqui a solução que a tecnologia .Net da Microsoft utiliza para paralelismo.

A partir da versão 4.0 do .Net Framework, foi introduzido um novo modelo para desenvolver aplicativos que realizem tarefas simultaneamente, chamado de Biblioteca Paralela de Tarefas, ou, Task Parallel Library (no original).

Diferentemente da abordagem tradicional para multitarefa, onde você pode criar e gerenciar um conjunto de tópicos em seu código, o novo modelo de programação paralela permite você se concentrar nas tarefas que você precisa para realizar e permite ao runtime criar e gerenciar as threads no seu lugar. Com isso, o desenvolvedor não precisa se preocupar em como será executado o código, se focando apenas na tarefa que precisa executar.

Abaixo está um exemplo de como fazer um loop para imprimir dez números inteiros na tela utilizando programação seqüencial e imprimir o mesmo loop de forma paralela (linguagem VB.NET).

Imports System.Threading.Tasks
Imports System.Threading

Module Module1

    Public Sub Main(ByVal args As String())
        executaSequencial(10)
        executaParalelo(10)

        Console.ReadKey()
    End Sub

    Private Sub escreverNumero(ByVal numero As Integer)
        Console.WriteLine(numero)
        Thread.Sleep(500)
    End Sub

    Private Sub executaSequencial(ByVal qtde As Integer)
        Dim sw As New Stopwatch()
        sw.Start()

        For i As Integer = 1 To qtde
            escreverNumero(i)
        Next

        sw.Stop()
        Console.WriteLine("Tempo execucao com for normal: " & sw.Elapsed.ToString)
    End Sub

    Private Sub executaParalelo(ByVal qtde As Integer)
        Dim sw As New Stopwatch()
        sw.Start()

        Parallel.For(1, qtde + 1, Sub(i As Integer) escreverNumero(i))

        sw.Stop()
        Console.WriteLine("Tempo execucao com for paralelo: " & sw.Elapsed.ToString)
    End Sub

End Module


Após executar o código, será impresso na tela o seguinte resultado:


Podemos perceber a diferença no tempo de execução entre as funções. O detalhe a ser levado em consideração é que mesmo em computadores com apenas um processador com um núcleo, o código escrito para ser paralelo é executado mais rápido que o seqüencial.

Irei demonstrar como escrever o mesmo loop utilizando a tecnologia Linq.


   Private Sub executaSequencialLinq(ByVal qtde As Integer)
        Dim sw As New Stopwatch()
        Dim valores = Enumerable.Range(1, qtde)

        sw.Start()
        Dim numeros = From n In valores
                      Where n >= 1 And n <= qtde
                      Select retornaNum(n)

        For Each num In numeros
            Console.WriteLine(num)
        Next

        sw.Stop()
        Console.WriteLine("Tempo execucao com for normal usando Linq: " & sw.Elapsed.ToString)
    End Sub

    Private Sub executaParaleloLinq(ByVal qtde As Integer)
        Dim sw As New Stopwatch()
        Dim valores = Enumerable.Range(1, qtde)

        sw.Start()
        Dim numeros = From n In valores.AsParallel
                      Where n >= 1 And n <= qtde
                      Select retornaNum(n)

        For Each num In numeros
            Console.WriteLine(num)
        Next

        sw.Stop()
        Console.WriteLine("Tempo execucao com for paralelo usando Linq: " & sw.Elapsed.ToString)
    End Sub

    Private Function retornaNum(ByVal numero As Integer) As Integer
        Thread.Sleep(500)
        Return numero
    End Function


Após executar o código, será impresso na tela o seguinte resultado:


Não tem muita diferença. Mas a vantagem de utilizarmos Linq é que podemos utilizar algumas funções no paralelismo. Se desejar imprimir de maneira ordenada a lista dos números do código paralelo, é só utilizar a função AsOrdered após a função AsParallel.



Não há perda significativa de performance se imprimir ordenado ou desordenado. Podemos também definir até que nível de paralelismo será utilizado, bastando utilizar a função WithDegreeOfParallelism passando como parâmetro a quantidade de processadores a serem utilizados.

Como pudemos perceber, o paralelismo reduz notoriamente o tempo de processamento do programa. Nos aplicativos que trabalham um enorme volume de dados, é interessante implementar a programação paralela diminuindo o tempo de resposta e, consequentemente, a energia gasta pela máquina.