Concurrent Programming == Parallel Programming? – pill #1
-
Concurrencia, ese hijo pródigo al que no veíamos desde los 90 y que de repente llama a nuestra puerta
Se indica que, para poder portar una aplicación a una arquitectura multicore (o eminentemente paralela, podríamos entender un SMP cualquiera, no necesariamente un CMP), los programas deberían escribirse de tal forma que escalaran de manera natural, es decir que estuverian caracterizados por una «concurrencia latente» -es curioso ver estos dos términos juntos- de este modo, las susochidas arquitecturas podrán ser usadas (sin el perjuicio archiconocido de los pipelines «recortados», las frecuencias de reloj reducidas, etc).
Hay un detalle revelador, que ya he visto en más de un documento editado por la gente de Microsoft, Joe Duffy, entre otros. Y es la extraña simbiosis que establecen entre concurrencia y paralelismo. He deducido, no se si erróneamente, que el paralelismo es el uso de la concurrencia para descomponer una operación en elementos cuyo grano sea más fino, elementos independientes, elementos capaces de ejecutarse de manera separada. ¿Es el paralelismo un caso especial de la concurrencia? Según estamos acostumbrados (aplicaciones de altas prestaciones) esto no se aplica, lo que da que pensar que :
(1) El modelo de programación usado en las aplicaciones de altas prestaciones, es poco adecuado
(2) Hemos estado trabajando con la «píldora azul» hasta que la industria nos ha obligado a tomar la «píldora roja».
Es más uno de los temas más estudiados, en el campo de la supercomputación es la «escalabilidad» de las aplicaciones. Se supone que de ser paralelismo y concurrencia un mismo concepto entonces, detalles sobre el lenguaje a parte, no tendría mucho sentido este estudio. Cierto es que con el modelo de paso de mensajes la cuestión de la granularidad se ha visto muy perjudicada.
Entonces ¿qué ocurre con las aplicaciones de segunda fila? (nota: una aplicación de segunda es una aplicación escrita con lógica secuencia, para un procesador «secuencial»). La buena noticia es que : ES POSIBLE, si, aleluya, es posible coger un código de segunda fila y adaptarlo para que acoja en su seno a la concurrencia. Bienvenido hijo pródigo. Las herramientas para pensar en cómo adaptar el código a esos elementos disjutos capaces de ejecutarse independientemente (de lo que hablé antes) son agentes y tareas. Ni más ni menos, pero no cualquier agente, sino agentes herméticos, capaces de aislar su comportamiento (esto sólo lo hacen para ligar con la caché L2, no os creais que es por principios). Eso sí, con los agentitos va a ser fácil recoger a la concurrencia pero se va a complicar en demasía la depuración de código. Basta con pensar en cuando los agentes comiencen a abordar tareas que afecten a otros agentitos.
Claro, que cuando digo que la concurrencia será fácil de empotrar en las aplicaciones de segunda fila, me refiero a las aplicaciones con las que suelo trabajar : tratamiento de imágenes donde el paralelismo es muy «fácil» de extraer, pero si nos detenemos un rato y pensamos en las aplicaciones como los algoritmos que procesan video o sonido … la cosa puede no ser tan liviana. Para esto existen modificaciones del lenguaje como LINQ en C# que puede ser de bastante utilidad, también está Mathlab (para los que lo sepan domar). Asi que como el paralelismo está derivado a «librerías» los programas que usen estas librerías podrán gozar lujuriosamente de cierta escalabilidad casi de manera directa.
No obstante la concurrencia no deja de ser peligrosa, su uso puede agilizar -como es obvio- la ejecución (haciendo más reactiva a una aplicación, por ejemplo) pero su uso para refactorizar toda la lógica es peligroso: sincronización, bloqueos, condiciones de carrera, etc, pueden degradar el rendimiento e incluso dar al traste con toda la aplicación.