Programação paralela no .NET Framework 4 – Parte I

Introdução

O avanço de tecnologia nos últimos anos forneceu, a baixo custo, acesso  a workstations com inúmeros CPUs. Facilmente encontramos hoje máquinas clientes com 2, 4 e até 8 núcleos, sem considerar os “super-servidores” com até 36 processadores :)

Da wikipedia:

A Unidade central de processamento (CPU, de acordo com as iniciais em inglês) ou o processador é a parte de um sistema de computador que executa as instruções de um programa de computador, e é o elemento primordial na execução das funções de um computador. Este termo tem sido usado na indústria de computadores pelo menos desde o início dos anos 1960[1]. A forma, desenho e implementação de CPUs têm mudado dramaticamente desde os primeiros exemplos, mas o seu funcionamento fundamental permanece o mesmo.

Fazendo uma analogia, seria muito interessante delegarmos tarefas no mundo real que podem ser executadas independentemente a pessoas diferentes, atingindo desta forma uma  maior performance / produtividade na sua execução.

A computação paralela se baseia na idéia que um problema maior pode ser dividido em problemas menores, sendo resolvidos de forma paralela. Este pensamento é utilizado há algum tempo por HPC (High-performance computing), e através das facilidades dos últimos anos, assim como a preocupação com consumo de energia, tornaram esta idéia mais atrativa e de fácil acesso a qualquer ambiente.

No .NET Framework

A plataforma .NET apresenta um runtime, bibliotecas e ferramentas para fornecer uma base de acesso fácil e rápido à programação paralela, sem trabalhar diretamente com threads e thread pool.

Esta série de posts irá apresentar todos os recursos disponíveis, iniciando os estudos pela TPL, ou Task Parallel Library.

Task Parallel Library

A TPL é um conjunto de tipos localizados no namespace System.Threading e System.Threading.Tasks, a partir da versão 4 do framework.

A partir da versão 4 do framework, o TPL é a maneira recomendada para escrever código paralelo e multithreaded.

http://msdn.microsoft.com/en-us/library/dd460717(v=VS.100).aspx

Task Parallelism

O termo “task parallelism”, ou em uma tradução live paralelismo de tarefas, se refere a uma ou mais tarefas sendo executadas de forma simultanea.

Considere uma tarefa como um método. A maneira mais fácil de executar tarefas de forma paralela é o código abaixo:

Parallel.Invoke(() => TrabalhoInicial(), () => TrabalhoSeguinte());
O que acontece de verdade?

Por trás nos panos, esta instrução instancia de forma implícita objetos do tipo Task, responsável por representar uma operação assíncrona, não exatamente paralela:

public class Task : IAsyncResult, IDisposable

É possível instanciar Tasks de forma explícita, sendo uma alternativa mais complexa ao Parallel.Invoke.

var task = new Task(() => TrabalhoInicial());
task.Start();

Outra opção de instanciar uma Task e já executar sua tarefa é:

var t = Task<int>.Factory.StartNew(() => TrabalhoInicialComValor());
var t2 = Task<int>.Factory.StartNew(() => TrabalhoSeguinteComValor());

A diferença básica entre as duas abordagens é que a primeira tem início conhecido, mais utilizado quando não queremos que a instanciação e o agendamento da execução ocorra em uma só operação, como na segunda abordagem.

Data Parallelism

Ainda parte da TPL, o Data Parallelism se refere a cenários onde a mesma operação deva ser executada paralelamente em elementos de uma coleção ou array, através de instruções paralelas For e ForEach. A idéia básica é pegar cada elemento da coleção (ou array) e trabalhar com diversas threads concomitantemente.

A classe-chave para este cenário é a System.Threading.Tasks.Parallel

// Sequential version            
foreach (var item in sourceCollection)
{
    Process(item);
}

// Parallel equivalent
Parallel.ForEach(sourceCollection, item => Process(item));

Complicado né? :)

Demonstração

Acesse aqui um vídeo com exemplos (screencast).

Cuidado!

Apesar da imensa vontade de sair codificando, tome cuidado com alguns problemas básicos de paralelismo. Neste link é possível conhecer algumas situações.

Abraços.

1 Comment

  • Andre, EStou lendo um arquivo com 10 mil linhas, e usando cada linha do arquivo para realizar alguns procedimentos. Cada linha demora em torno de 300 milesegundos apos ser lido para entao terminar seu procedimento. A impressao que tenho e que o paralell.foreach so executa um novo quando termina o anterior. O que posso fazer para executar os itens de uma unica vez?

Comments have been disabled for this content.