Você está na página 1de 14

Universidade Federal de Ouro Preto

Instituto de Ciências Exatas e Aplicadas

Departamento de Computação e Sistemas

Redução de complexidade usando paralelismo

Matheus Fellipe do Carmo Barros


Daniel Goldner Junior
Daniel Araújo
Vinícius Linhares

Professor - Fabianni Roberto Teles

João Monlevade
2018
SUMÁRIO

1 Introdução ​2

2 Paralelismo ​2

3 Redução complexidade ​5

4 Exemplos ​7

5 Conclusão ​11

6 Referências ​12

1
1 - Introdução

Os problemas com custo fatorial ou combinatório estão agrupados em uma


classe de complexidade não determinística polinomial - NP. Estes problemas não têm,
em geral, uma metodologia de solução prática, o que significa dizer que uma máquina
não pode resolvê-los em um tempo razoável, mesmo em pequenos tamanhos
(instâncias pequenas do problema). Assim, na teoria da complexidade, os problemas
estão divididos em várias classes de complexidade de acordo com os tempos de
execução em um sistema de processador único (ou uma máquina de Turing
determinística, para ser mais exato). Problemas cujo tempo de execução é polinomial
pertencem à classe P e são considerados tratáveis. Por outro lado, há problemas que
mesmo utilizando o melhor algoritmo determinístico conhecido ainda possui um tempo
de execução exponencial, e por isso são intratáveis. Neste cenário, mostrar que existe
uma forma de reduzir a complexidade de problemas através de uma técnica e que esta
pode ser aplicada à maior parte dos problemas, ou mesmo a todos eles, poderia
colocar as pesquisas ligadas a resolução de problemas em um nível mais elevado.
Inúmeras são as abordagens que buscam reduzir a complexidade descrita, inclusive
através da combinação de várias estratégias e técnicas. Entre estas abordagens está a
computação paralela.

2 - Paralelismo

Têm-se constatado a crescente oferta de equipamentos que proporcionam


ambientes de programação paralela, como os agregados de computadores, conhecidos
como ​clusters​. Reúnem-se várias máquinas, como computadores pessoais (PCs),
através de uma rede de comunicação de alto desempenho, tendo assim um ambiente
de programação paralela ou distribuída. Nesses ambientes, o poder computacional tem
aumentado tanto pelo aumento da velocidade de processamento dos processadores
quanto pelo aumento do número de processadores integrados ou agregados ao
sistema.
Neste contexto, é necessário caracterizar a forma de se executar tarefas
conhecida como processamento que pode ser sequencial, pipeline, vetorial, paralelo e
distribuído.

2.1 - Processamento sequencial

O processador lê um único fluxo de dados por vez e realiza uma operação por
unidade de tempo, ou seja, não se executa mais que uma operação por unidade de

2
tempo.

2.2 - Processamento pipeline

Pipeline é a divisão de uma função genérica em uma seqüência de k


sub-funções que podem ser implementadas por k módulos de hardware dedicados e
autônomos denominados estágios. Cada estágio é capaz de receber dados do estágio
anterior, operá-los e transmitir o resultado para o estágio seguinte. Dessa forma,
sucessivas execuções da função podem ser conduzidas pelas sub-funções, operando
por superposição (overlap),resultando no processamento pipeline.

2.3 - Processamento vetorial

Substitui-se um laço do programa que usa instruções escalares por um laço que
usa instruções vetoriais, levadas a cabo por um hardware específico, implementado
por pipeline. O processamento vetorial difere no fato de que os pipelines evoluíram
para instruções vetoriais.

2.4 - Processamento paralelo

É uma forma eficiente de processar informação a qual enfatiza a exploração de


eventos concorrentes na computação do processo. Pode-se caracterizar o
processamento paralelo quando existe um conjunto de máquinas sendo controladas
por um único sistema operacional. A realização de tarefas é levada a cabo por
determinação desse sistema que diz quem realiza o que.

2.5 - Processamento distribuído

No processamento distribuído há um conjunto de máquinas, cada uma com


seu próprio sistema operacional. Existem diversos processadores, diferentes ou
não, utilizando uma rede de comunicação. Os processadores trabalham
cooperativamente para que os recursos dispersos sejam utilizados na prestação
de serviços. Esses diversos processadores devem controlar os seus próprios
recursos.

3
2.6 - Programação Paralela

O paralelismo pode ser implícito ou explícito. O paralelismo implícito é tido como


aquele que é inerente ao próprio programa. Esse tipo de paralelismo, geralmente, é
identificado pelo sistema operacional. Portanto, cabe ao sistema operacional fazer a
análise de dependências, visando identificar partes ou pedaços do programa que
podem ser processados ao mesmo tempo, ou seja, podem ser paralelizados. A
independência é dada pela necessidade de acesso exclusivo aos dados.
Cabe ao Sistema Operacional e/ou compilador:
● Detectar o paralelismo potencial do sistema;
● Atribuir as tarefas para execução em paralelo;
● Controlar e sincronizar toda execução.

O paralelismo implícito tem como vantagens e/ou desvantagens:


● Libera o programador dos detalhes da execução paralela;
● Solução mais geral e mais flexível;
● Difícil conseguir uma solução mais eficiente para todos os casos.

O paralelismo explícito pode aparecer em três formas:


• Paralelismo através de dados (​data paralellism​) - muito comum em arquiteturas
matriciais, onde uma única instrução é executada por vários elementos processadores
sobre diversos fluxos de dados;
• Paralelismo por troca de mensagens (​message passing)​ - são encontrados em
arquiteturas de multiprocessadores, onde vários processadores estão envolvidos na
execução do programa, sendo necessário que se comuniquem. Nesses casos a maior
parte do processamento é local, mas há uma pequena parte do processamento que
consiste em troca de informação;
• Paralelismo através de variáveis comuns - também encontrado em arquiteturas
de multiprocessadores, onde a comunicação se faz através de variáveis comuns
(memória global), as quais substituem mecanismos de comunicação, onde os
processos trocam de informação através de acessos à memória, o que proporciona
uma comunicação rápida.
Cabe ao programador:
● Anotar as tarefas para execução em paralelo;
● Atribuir as tarefas aos processadores;
● Controlar a execução;
● Conhecer a arquitetura da máquina de forma a obter melhor performance.

O paralelismo explícito tem como vantagens e/ou desvantagens:

4
● Depende da experiência e capacidade do programador;
● Dificuldade de portabilidade entre diferentes arquiteturas.

3 - Redução Complexidade

Devido aos limites físicos dos recursos disponíveis no computador, não basta
identificar um problema e garantir que exista pelo menos uma solução para este, é
necessário saber se este pode ser resolvido efetivamente dentro de certos limites
referentes a tais recursos. A complexidade computacional consiste em uma função
matemática que depende do tamanho da entrada e dos recursos utilizados pelo
algoritmo, sendo o tempo e o espaço (quantidade de memória) os recursos que
comumente são avaliados para mensuração da mesma, em outras palavras, segundo
Hwang e Jotwani (2010, p 30) a complexidade de um algoritmo para resolver um
problema de tamanho s em um computador é determinada pelo tempo de execução e
pelo espaço requerido.
Complexidade de tempo
Denominada também de complexidade temporal, ela consiste em uma função
que varia de acordo com o tamanho da entrada para o problema, sendo mensurada
pelo número de unidades de tempo necessárias a execução do algoritmo
Complexidade de espaço
Também chamada de complexidade espacial, ela refere-se à quantidade de
memória requerida pelo algoritmo como uma função do tamanho do problema, sendo
mensurada como uma unidade de espaço para cada registro necessário para um
cálculo individual
Ao estudar a complexidade de um algoritmo pode-se avaliá-la sobre a ótica de que o
algoritmo proposto para resolver o problema poderá solucioná-lo em 3(três) diferentes
cenários, sendo eles:

Várias são as métricas utilizadas para analisar um algoritmo paralelo, destacando-se:


tempo de execução; overhead; speedup; eficiência e custo.
Exemplo:
O problema consiste em achar um determinado elemento x em uma lista L de n
elementos ordenados ou não ordenados, onde L = (a1, a2,..., an), ou mais
precisamente, dado um número x em uma lista L qualquer, encontrar um índice j tal
que L[j] = x.

5
Para efeito de análise será abordado apenas o caso em que os elementos da
lista L estão desordenados,O Algoritmo 1 realiza este processo de forma sequencial,
possuindo complexidade de tempo igual a O (n), para o pior caso.
Para construção do algoritmo paralelo para o problema da pesquisa utilizamos uma
técnica de busca em blocos de elementos, no qual um conjunto de p processadores,
fará uma pesquisa em um bloco de tamanho b, onde b = p, em d iterações, sendo d =
log n, onde:

sendo p uma função de qualidade fp(n) a qual determina o número de unidades de


processamento(threads) utilizadas e que garantirão a redução de complexidade
pretendida, em uma lista de n elementos

O Algoritmo 2 realiza o processo de pesquisa, particionando a lista L em blocos de


elementos de tamanho b, onde cada thread irá verificar um elemento do bloco. A
variável k é compartilhada por todas as threads, tendo sido atribuído o valor (-1) a ela,
indicando que o elemento não foi encontrado. Assim, quando alguma thread encontrar
o valor que está sendo procurado, esta variável é modificada, indicando em que
posição da lista L ele se encontra, forçando todas as demais threads a cessarem a
busca, conforme linhas 5 e 8. O processo irá ser realizado, no pior caso, até que toda a
lista seja verificada ou até o elemento ser encontrado, ou seja, em​ log n​ passos.

6
Analisando agora a quantidade de iterações necessárias para percorrer todo o conjunto
de elementos de L, está é expressa por O(log n) passos, logo têm-se que:
O(Pesquisa) = O(Computações por Nível) x O(Iterações)
O(Pesquisa) = O(1).O(log n)
O(Pesquisa) = O(log n), para o pior caso.
Há uma redução na ordem de grandeza da complexidade de tempo do Problema da
Pesquisa, haja vista que o melhor algoritmo seqüencial para o referido problema é
O(n), enquanto o algoritmo paralelo descrito (ALGORITMO 2) possui complexidade
O(log n).

4 - Exemplos
Para fazer uma comparação de complexidade, foi se estudado o algoritmo do
Crivo de Eratóstenes, que é um algoritmo clássico para encontrar todos os números
primos menores ou iguais a um número inteiro positivo ​n.
O estudo consiste na comparação entre o algoritmo executado de forma serial e
​ e processadores.
paralelo, usando um número ​p d

4.1 -​ ​Crivo de Ertóstenes


O Crivo de Eratóstenes (276 A.C. - 194 A.C.) é um método simples e prático de
se encontrar números primos até um certo valor limite n. O algoritmo começa com a
lista de números naturais de 2 até ​n . A cada passo, o menor fator primo (ainda não

7
utilizado) ​p é escolhido e todos os múltiplos de ​p são removidos da lista. O algoritmo
termina quando todos os fatores primos menores ou iguais a ​√n​ tenham sido utilizados.
A ideia do algoritmo usado é passar como parâmetro um determinado número ​n​, e
como resultado se obtém o número de números primos do intervalo de 2 até ​n.​

4.2 ​- ​Algoritmo Serial

8
4.2.1 - Análise de Complexidade
A análise de complexidade do algoritmo levará em conta o limite superior ​n da
lista de primos.

Tempo: ​a complexidade de tempo ​T(n) do Crivo de Eratóstenes no pior caso, melhor


caso e caso médio é:

T(n) =O(n*log log n)

Espaço: ​a complexidade de espaço ​E(n) do algoritmo no pior caso, melhor caso e caso
médio é:

E(n)=O(n)

4.3 - Algoritmo Paralelo


O paralelismo do Crivo de Eratóstenes consiste em dividir a entrada entre os
processos, assim, atribuindo para cada processo, uma parcela da lista de números.

9
10
4.3.1 - Análise de Complexidade
A análise de complexidade do algoritmo paralelo levará em conta o limite
superior ​n​ da lista de primos e número de processos ​p.​
.
Tempo: ​a complexidade de tempo ​T(n) do Crivo de Eratóstenes paralelo no pior caso,
melhor caso e caso médio é:

T(n) =O((n*log log n)/p)

Espaço: ​a complexidade de espaço ​E(n) do algoritmo paralelo no pior caso, melhor


caso e caso médio é:

E(n)=O(n/p)

4.4 - Serial x Paralelo

A comparação dos resultados obtidos mostram que o tempo de execução do


Crivo de Eratóstenes de forma paralela se mostrou a alternativa mais escalável,
apresentando um desempenho superior ao serial.
A utilização de algoritmos paralelos pode apresentar uma alternativa interessante para
a resolução de problemas de alto custo computacional. Caso o algoritmo paralelo seja
bem projetado, ele pode viabilizar soluções que não seriam possíveis utilizando apenas
algoritmos sequenciais.

5 - Conclusão

Paralelismo é um dos grandes desafios da computação, que voltou a ganhar


importância nos últimos anos com a abundância e barateamento de máquinas
commodity permitindo a construção de clusters e o advento de GPGPU’s capazes de
processamento paralelo em massa, permitindo que problemas cada vez maiores
possam ser resolvidos eficientemente e com custo menor. No entanto, tanto
arquiteturas de hardware como técnicas de programação tiveram de evoluir para
acompanhar esse ganho massivo em paralelismo, pois técnicas automatizadas de
paralelismo ainda estão longe de resolver todos os problemas existentes com
desempenho aceitável, cabendo ao programador analisar cada situação. A
programação paralela depende do entendimento do problema a ser resolvido, aliado à

11
uma estratégia de paralelismo restrita aos limites dos recursos disponíveis, e suporte
em hardware.

REFERÊNCIAS

NOBRE, R. H. ​PARALELISMO COMO SOLUÇÃO PARA REDUÇÃO DE


COMPLEXIDADE DE PROBLEMAS COMBINATORIAIS. Disponível em
<http://www.uece.br/mpcomp/index.php/arquivos/doc_download/265-dissertacao83-par
alelismo-como-solucao-para-reducao-de-complexidade-de-problemas-combinatoriais>
Acesso em 07 de setembro de 2018.

ROCHA, R. ​FUNDAMENTOS DA COMPUTAÇÃO PARALELA. ​Disponível em


<https://www.dcc.fc.up.pt/~ricroc/aulas/0607/cp/apontamentos/parteI.pdf> Acesso em
08 de setembro de 2018.

PAULO A. S. VELOSO. ​ANÁLISE DA COMPLEXIDADE DE ALGORITMOS


PARALELOS. ​Disponível em
<http://www.lbd.dcc.ufmg.br/colecoes/erad-rs/2002/004.pdf> Acesso em 10 de
setembro de 2018.

12
JÚNIOR, Fernando Antonio Fernandes; ZIVIANI, Nivio. ​Projeto e Análise de
Algoritmos​. 2006. Disponível em
<​http://homepages.dcc.ufmg.br/~nivio/cursos/pa06/tp4/tp42/tp42.pdf​> Acesso em 09
de setembro de 2018.

13