Beruflich Dokumente
Kultur Dokumente
3
I. Definición y fundamentación del problema
4
algoritmos con fuertes restricciones temporales. Son sistemas cada vez más complejos
que requieren mayor tiempo de cómputo.
5
II. Algoritmos paralelos
Definición.
En
informática,
cuando
hablamos
de
algoritmo
paralelo
nos
estamos
refiriendo
a
un
algoritmo
que
puede
ser
ejecutado
por
partes,
o
de
un
modo
más
formal,
el
tipo
de
algoritmo
en
el
que
programa,
procesador
y
puertos
de
comunicación
interaccionan
intercambiando
tareas
a
través
de
canales
para
la
resolución
de
un
problema.
Dada
la
definición,
instintivamente
nos
preguntamos
¿Hasta
qué
punto
podemos
dividir
la
tarea
en
otras
pequeñas
tareas
paralelizadas?
Para
contestar
a
esta
pregunta,
tenemos
que
comprender
el
concepto
de
granularidad.
La
granularidad
de
un
sistema,
entendiendo
sistema
como
la
conjunción
de
software
(nuestro
algoritmo)
con
hardware
(nuestro
equipo
multiprocesador),
indica
la
cantidad
de
computación
y
datos
asignados
a
cada
procesador.
La
granularidad
está
determinada
por
el
número
y
el
tamaño
de
las
tareas
en
el
cual
un
problema
es
descompuesto,
pudiendo
distinguir
así
entre
grano
fino
y
grano
grueso.
Grano
fino
corresponde
a
una
asignación
de
pocos
datos
por
procesador
o
a
una
baja
computación
entre
comunicaciones.
Grano
grueso,
por
el
contrario,
es
la
granularidad
que
se
da
cuando
existe
una
gran
carga
de
datos
por
cada
procesador
o
bien
se
realiza
mucha
computación
entre
comunicaciones.
En
cuanto
a
algoritmos,
solo
nos
interesará
la
programación
paralela
cuando
el
sistema
sea
de
grano
grueso,
ya
que
es
preferible
una
cantidad
de
datos
a
procesar
aceptable
con
pocos
hilos
de
proceso
que
numerosos
procesadores
con
escasa
cantidad
de
datos
a
procesar,
con
la
información
muy
dividida.
Algunos
algoritmos
son
más
fáciles
de
dividir
en
partes
que
otros,
así
podemos
poner
como
ejemplo
de
un
problema
difícilmente
paralelizable
el
problema
de
los
tres
cuerpos,
que
consiste
en
determinar,
a
partir
de
las
posiciones
y
velocidades
de
éstos
los
resultados
de
la
interacción
de
tres
cuerpos
en
un
campo
de
fuerzas
aislado.
Este
tipo
de
problemas
se
conoce
como
problemas
inherentemente
secuenciales.
Otros
problemas
sin
embargo
son
fácilmente
divisibles
en
subprocesos,
como
el
algoritmo
ray
tracing,
propuesto
por
primera
vez
en
1968,
por
Apple
y
que
actualmente
es
una
de
las
simulaciones
más
completas
en
cuanto
a
modelos
de
iluminación
y
reflexión
por
computadora.
6
!"#$%&%&'()'*$+,-%./,&'0*-*$)$,&
Aceleración según la ley de Amdahl
ts
fts (1 - f)ts
(b) Multiple
processors
p processors
tp (1 - f)ts /p
Introducción a la Computación Paralela 43
figura 2.1
Punto
de
saturación.
Ley
de
Amdahl.
Debemos
tener
cuidado
con
la
granularidad
de
nuestro
algoritmo.
No
podemos
olvidar
que
por
mucho
que
lo
dividamos,
siempre
se
va
a
mantener
una
parte
secuencial
por
lo
que
la
división
en
un
excesivo
número
de
subprogramas
puede
llevar
a
un
punto
de
saturación,
en
el
que
el
uso
de
más
procesadores
no
induce
mejora
alguna.
Para
averiguar
la
mejora
máxima
del
sistema
cuando
solo
una
de
las
divisiones
de
éste
es
mejorada
se
utiliza
la
ley
de
Amdahl:
<<La mejora obtenida en el rendimiento de un sistema debido a la alteración de uno de sus
componentes está limitada por la fracción de tiempo que se utiliza dicho componente>>
Matemáticamente:
Tuso mejorado
(
Tejecución mejorado = Tejecución antiguo ⋅ (1 − Tuso mejorado + ) f mejora
con:
€ Tejecución antiguo
Gananciavelocidad =
Tejecución mejorado
7
O
trasladado
a
otras
palabras,
el
incremento
de
velocidad
de
una
tarea
utilizando
varias
unidades
de
proceso
en
computación
distribuida
(concepto
que
introduciremos
más
adelante)
está
limitado
por
la
mínima
fracción
secuencial
de
la
tarea,
momento
este
en
el
que
se
llega
al
punto
de
saturación
y
no
se
puede
paralelizar
más
el
algoritmo.
Esta
ley
nos
indica
que
dada
una
tarea
con
T
divisiones
independientes,
tendrán
mayores
índices
de
mejora
aquellas
partes
que
contenga
más
datos,
que
necesiten
más
tiempo
de
ejecución,
de
ahí
el
principio:
“Siempre se debe optimizar el caso más común”
El
coste
representa
el
trabajo
realizado
por
todo
el
sistema
para
la
resolución
del
problema.
Como
hemos
visto,
los
algoritmos
paralelos
no
solo
tienen
un
coste
en
términos
del
espacio
(memoria)
y
tiempo
(ciclos
de
procesador),
sino
que
también
necesitan
optimizar
la
comunicación
entre
diferentes
unidades
de
procesamiento.
Esto
se
consigue
mediante
la
aplicación
de
dos
técnicas
ampliamente
extendidas,
memoria
compartida
o
paso
de
mensajes.
En
memoria
compartida
nos
encontramos
con
un
único
espacio
de
memoria.
Todos
los
procesadores
tienen
acceso
a
la
memoria
a
través
de
una
red
de
conexión
que
puede
ser
un
bus,
una
red
de
barras
cruzadas
o
una
red
multietapa.
• Redes
basadas
en
buses:
Es
simple
y
con
buena
capacidad
de
acceso
a
memoria.
En
contraposición,
la
cantidad
de
datos
a
transmitir
limitada
por
el
bus,
y
el
rendimiento
se
satura
para
un
número
de
procesadores
bajo.
Esto
último
se
puede
solventar
mediante
memorias
locales
de
caché
en
los
procesadores
(ver
figura
2.2)
• Redes
de
barras
cruzadas:
Conecta
un
número
determinado
de
procesadores
figura 2.2
con
una
serie
de
módulos
de
memoria
mediante
el
uso
de
una
red
de
conmutadores.
• Conforme
crece
el
número
de
procesadores
la
complejidad
de
la
red
aumenta
cuadráticamente
por
lo
que
no
son
muy
escalables.
• Redes
de
interconexión
multietapa:
Es
un
tipo
de
red
intermedia
en
términos
de
escalabilidad
en
costo
y
rendimiento
La
técnica
memoria
compartida
necesita
del
uso
de
cerrojos
(latches)
en
los
datos
para
impedir
que
un
bloque
de
información
se
modifique
simultáneamente
por
dos
o
más
procesadores,
por
lo
que
se
produce
un
coste
extra
en
ciclos
de
procesador.
8
Con
memoria
distribuida
el
computador
se
convierte
básicamente
en
una
colección
de
procesadores
secuenciales
que
trabajan
conjuntamente,
donde
cada
procesador
tiene
su
propia
memoria
local
(ver
figura
2.3).
Se
utiliza
el
paso
de
mensajes
para
intercambiar
datos
entre
procesadores
(acceso
a
memoria
de
otro
procesador),
normalmente
mediante
redes
o
sistemas
de
interconexión
de
alta
velocidad.
Independientemente
de
esta
red,
cada
procesador
tiene
acceso
rápido
a
su
propia
memoria.
Los
datos
son
intercambiados
entre
los
nodos
como
mensajes
a
través
de
la
red,
por
lo
que
las
redes
de
ordenadores
cobran
especial
interés
para
la
resolución
de
problemas
con
este
tipo
de
algoritmos
paralelos.
La
técnica
paso
de
mensajes
añade
un
coste
al
bus,
que
se
traduce
en
figura 2.3
memoria
adicional
para
las
colas
y
los
mensajes.
A
la
hora
de
diseñar
un
procesador
paralelo
conviene
usar
canales
especiales
para
que
el
coste
de
la
comunicación
sea
lo
menor
posible.
Ventajas
de
la
computación
paralela.
9
III. Medida de la eficiencia
Tiempo
de
ejecución
de
un
programa
paralelo.
En
el
caso
de
un
programa
secuencial,
el
tiempo
de
ejecución
es
el
tiempo
que
transcurre
desde
que
se
inicia
la
ejecución
hasta
que
finaliza.
En
cambio,
en
el
caso
de
un
programa
paralelo
es
el
tiempo
transcurrido
desde
que
comienza
la
ejecución
por
parte
del
primer
procesador
(primer
hilo
que
se
lanza)
hasta
el
momento
en
que
el
último
procesador
finaliza
su
ejecución.
No
siempre
va
a
ser
fácil
determinar
el
orden
en
que
los
procesadores
empiezan
y
acaban,
ya
que
hemos
de
tener
en
cuenta
la
existencia
de
una
serie
de
puntos
de
sincronización
a
los
que
llegan
los
distintos
procesos
en
un
orden
indefinido.
Por
ellos,
estos
puntos
de
sincronización
en
memoria
tienen
una
duración
que
no
siempre
podemos
determinar.
A
priori
el
tiempo
de
ejecución
vendrá
determinado
por:
Por
tanto,
el
tiempo
de
ejecución
se
puede
expresar
de
una
forma
más
detallada:
10
Reducción
de
prestaciones.
Límites.
• Código
secuencial:
Como
ya
hemos
comentado
en
apartados
anteriores,
puede
haber
parte
imposible
de
paralelizar.
Un
ejemplo
puede
ser
la
inicialización
de
variables.
• Contención
de
memoria:
Problema
que
se
da
con
el
acceso
a
datos
comunes
o
que
están
en
el
mismo
bloque
de
memoria.
En
el
caso
en
que
los
datos
son
de
lectura,
normalmente
no
se
da
ese
problema.
• Tiempo
de
creación
de
procesos:
Cuantos
más
subprocesos
se
quieran
crear,
más
tarda
el
programa
en
ponerlos
en
marcha.
El
coste
de
creación
de
los
procesos
puede
ser
importante
si
la
granularidad
de
éstos
es
pequeña.
• Comunicaciones:
Como
hemos
mencionado,
es
el
tiempo
de
transferencia
de
datos
entre
procesadores.
• Tiempo
de
sincronización:
Se
da
cuando
un
proceso
tiene
que
esperar
a
que
estén
disponibles
datos
procesados
por
otro.
• Desbalanceo
de
la
carga:
Se
define
como
la
carencia
de
una
distribución
equitativa
del
volumen
de
computación
entre
todos
los
procesadores.
Puede
darse
que
el
volumen
de
datos
varíe
a
lo
largo
de
la
ejecución,
lo
que
haría
necesario
algún
tipo
de
balanceo
dinámico.
Ganancia
de
velocidad.
Speed-up.
Fundamentalmente
el
Speed-‐Up
es
una
técnica
de
la
que
se
obtiene
una
relación
de
mejora
entre
el
tiempo
de
ejecución
de
un
programa
secuencial
(con
un
solo
procesador)
y
en
paralelo
(con
p
procesadores).
Viene
definido
por
la
siguiente
fórmula:
t(n)
Speed-Up:
S(n, p) =
t(n, p)
A
partir
de
esta
fórmula
podemos
€ pensar
aplicando
una
lógica
sencilla
que
el
Speed-‐Up
simplemente
corresponderá
con
el
número
de
procesadores
del
algoritmo
paralelo.
Esta
afirmación
se
conoce
como
Speed-Up
ideal
y
está
considerada
como
una
buenísima
escalabilidad
del
algoritmo.
Sin
embargo,
en
la
práctica
es
bastante
complicado
ya
que
conduciría
a
una
ganancia
de
velocidad
lineal,
donde
doblando
el
número
de
procesadores
se
doblara
la
velocidad
de
cómputo.
11
300
250
200
50
0
0
32
64
96
128
160
192
224
256
figura 3.1
El
valor
máximo
que
puede
alcanzar
es
uno,
que
corresponde
con
el
índice
de
máximo
aprovechamiento,
100%.
Normalmente,
al
aumentar
el
número
de
procesadores
el
índice
€ de
eficiencia
se
aleja
del
valor
de
máximo
aprovechamiento;
en
cambio,
para
un
número
de
procesadores
determinado,
aumentará
conforme
aumente
el
tamaño
del
problema…
12
Distribución
del
trabajo.
Mapeo
y
equilibrado
de
carga.
13
Aplicación
práctica
de
conceptos.
A
partir
de
los
conceptos
previamente
expuestos
vamos
a
proceder
a
comentar
algunos
aspectos
de
un
algoritmo:
“búsqueda
de
un
archivo
de
manera
paralelizada”,
implementado
por
José
Carlos
Rodríguez.
import java.io.File;
public class Busqueda extends Thread
{
String nombreBuscar;
File[] entradas; Declaraciones
previas…
public Busqueda(String nombreBuscar, File ruta)
{
entradas = ruta.listFiles();
this.nombreBuscar=nombreBuscar;
}
@Override
public void run()
{
String nombreArchivo;
String nombre[];
for (File entrada : entradas) Para
cada
una
de
las
{ entradas
if(entrada.isDirectory()) Comprueba
si
la
entrada
{ es
una
carpeta.
En
caso
new Busqueda(nombreBuscar, entrada).start(); afirmativo
inicia
un
nuevo
proceso
de
} búsqueda.
if(entrada.isFile()) Comprueba
si
entrada
es
{ un
fichero.
En
caso
nombre=entrada.getName().split("[.]"); afirmativo
comprueba
si
tiene
el
nombre
nombreArchivo=nombre[0];
buscado.
En
caso
if(nombreArchivo.equals(nombreBuscar)) afirmativo
devuelve
{ ubicación.
System.out.println("Archivo Encontrado
en:\n\n");
System.out.println(entrada+"\n\n");
}
}
}
}
14
Por
cada
directorio
que
se
encuentre
en
el
nivel,
se
accede
a
éste
mediante
un
nuevo
proceso
que
lanza
de
nuevo
el
algoritmo
de
búsqueda
comparando
cada
elemento
de
la
lista
de
ficheros
con
el
buscado.
Es
posible
que
con
un
algoritmo
con
balanceo
dinámico
de
la
carga,
que
reparta
rápidamente
las
cargas
de
trabajo
entre
los
distintos
procesadores
las
prestaciones
se
mantuvieran,
pero
en
cualquier
caso
estamos
hablando
de
una
alta
complejidad
del
programa
para
mantener
las
prestaciones
de
antes
de
paralelizar
el
algoritmo.
Caso
tercero:
Muchos
ficheros
y
pocos
directorios
15
Caso
cuarto:
Muchos
ficheros
y
muchos
directorios
En
este
caso
tenemos
los
beneficios
del
caso
inmediatamente
anterior
a
este,
como
la
baja
granularidad
y
la
buena
ganancia
de
velocidad
al
ejecutar
varios
hilos
simultáneamente,
pero
perdemos
algunos
otros
beneficios
ya
que
tenemos
una
bajada
de
prestaciones
debida
a
los
tiempos
de
comunicación
entre
procesadores
y
de
creación
de
procesos.
Dicho
esto,
en
este
caso
también
sería
apropiado
el
uso
de
algoritmos
paralelos
ya
que
podemos
obtener
una
buena
ganancia
en
velocidad
sobre
todo
si,
aun
siendo
ambas
altas,
la
cantidad
de
ficheros
es
muy
elevada
en
comparación
con
el
número
de
directorios.
Como
conclusión,
extensible
a
la
gran
mayoría
de
los
programas,
la
paralelización
de
un
algoritmo
solo
se
justifica
cuando
exista
una
fuerte
demanda
de
capacidad
de
cómputo,
y
será
prohibitivo
su
uso
cuando
estemos
ante
algoritmos
con
poco
consumo
de
recursos
y/o
muy
subdivididos.
16
IV. Bibliografía
Cabe destacar también que me ha sido de ayuda poder contrastar información con
algunos puntos de la Tesis Doctoral sobre Algoritmos Paralelos de D. Rafael Arturo
Trujillo Rasúa, de la Universidad Politécnica de Valencia.
17