Elemar DEV

Tecnologia e desenvolvimento

Fundamentos de PPL (C++) – Parte 2 – parallel_for e combinable

Olá. Tudo certo?!

No post anterior, mostrei como criar tasks para execução em paralelo, em C++. usando PPL.

Nesse post, mostro como utilizar duas importantes ferramentas:

  1. parallel_for – para execução de um loop paralelo;
  2. combinable – para criação de resultados  “combinados” de diversas threads.

Contando os “primos” em um intervalo

Comecemos, com o exemplo completo desse post:

#include <Windows.h>
#include <iostream>
#include <ppl.h>

using namespace std;
using namespace concurrency;

template <typename TFunction>
__int64 time_call(TFunction&& function)
{
	__int64 begin = GetTickCount();
	function();
	return GetTickCount() - begin;
}

bool IsPrime(int number){

	if (number < 2) return false;
	if (number == 2) return true;
	if (number % 2 == 0) return false;
	
	for (int i=3; (i*i)<=number; i+=2){
		if (number % i == 0 ) return false;
	}

	return true;
}

void NoParallel()
{
	int count = 0;

	for (int i = 0; i < 30000000; i++)
		if (IsPrime(i))
			count ++;

	cout << "NoParallel Count = " << count << endl;
}

void Parallel()
{
	combinable<int> count([](){ return 0; });
	parallel_for(0, 30000000, 1, [&](int i) {
		if (IsPrime(i))
			count.local() ++;
	});
	

	cout << "Parallel Count = " 
		<< count.combine(plus<int>()) 
		<< endl;
}

int main()
{
	auto noParallelTime = time_call(NoParallel);
	cout 
		<< "Total time (NoParallel): " << noParallelTime << "ms."
		<< endl;

	auto parallelTime = time_call(Parallel);
	cout 
		<< "Total time (Parallel): " << parallelTime << "ms."
		<< endl;
}

Como pode ver, estamos contando a quantidade de primos em um dado intervalo, com e sem paralelismo. Além disso, apresento o tempo consumido para cada abordagem.

parallelresult

Bela diferença, não acham?

Explicando parallel_for

A função parallel_for utiliza multiplos cores, se disponíveis, para processar um determinado intervalo de índices.

A dinâmica é simples: substituimos loops for por chamadas a parallel_for, convertendo o corpo do loop em uma expressão lambda.

No exemplo, os dois primeiros argumentos especificam os limites do for. O primeiro argumento é o menor índice que será processado. O segundo argumento é o limite exclusivo superior. O terceiro argumento é o “passo” do loop. Por fim, o quarto argumento é a expressão lambda (poderia ser uma função) que deverá ser executada para cada índice.

Explicando combinable

Converter “cumulativos sequenciais” para processamento paralelo não é tarefa simples. Perceba que, nesse exemplo, a conversão simples do corpo do loop não seria suficiente. Afinal, a variável “count” é compartilhada em todas as iterações.

Controlar acesso a variável (para que não ocorra em paralelo) não é uma alternativa viável. Afinal, o resultado dessa abordagem seria inferior ao da abordagem sequencial, pois o custo da sincronização seria proibitivo.

Solução?! Dividir para conquistar. Ou seja, calcular totais “por core” e, no final de tudo, somar os resultados. PPL facilita essa abordagem através da classe combinable.

No exemplo, count é uma instância de combinable que mantém valores separados para cada thread. O valor inicial, para cada thread, é determinado pela função que passamos no construtor. No final de todo processamento, podemos utilizar o método combine para juntar os resultados “por thread”.

Era isso.

3 comentários em “Fundamentos de PPL (C++) – Parte 2 – parallel_for e combinable

  1. elemarjr
    10/03/2013

    Para quem estiver buscando equivalente com TPL, em .net http://elemarjr.net/2011/09/04/parallel-aggregation-patterns-com-parallel-loops/

  2. Marcos Freccia
    10/03/2013

    Apesar de não ser desenvolvedor acho muito legal ver que existe tais funções dentro de uma linguagem de programação, uma pena é que nem todo mundo conhece esse poder e acaba por não utilizar.

    Mas uma duvida que tenho é: É possível limitar no código a quantidade de cores a ser utilizados quando se está realizando algum trabalho?

    Ótimo Post!!

    Abraços.

    • elemarjr
      10/03/2013

      Tanto a PPL (C++), quanto a TPL (.net) permitem a definição do número máximo de cores. Entretanto, não considero isso uma boa prática.

      BTW, bem-vindo ao RS

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às 10/03/2013 por em Post e marcado , , .

Estatísticas

  • 628,170 hits
%d blogueiros gostam disto: