Sunteți pe pagina 1din 11

Universidad Nacional de Ingenieria

Sistemas Concurrentes y Distribuidos

Teorica 1

Anthony Miranda Gil

T HE C LOJURE WAY

Periodo 2017-II
The Clojure Way
holacaracola

holacaracola

Índice

Índice 1

1. Clojure 2

2. Conceptos y Caracterı́stica 2
2.1. Programación Funcional . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.1.1. Programación puramente funcional . . . . . . . . . . . . . . . 3
2.1.2. Enfoque de Clojure . . . . . . . . . . . . . . . . . . . . . . . . 4

3. Inmutabilidad 4

4. Administración del estado 6


4.1. Estado e identidad: Separar la Identidad del Estado . . . . . . . . . . 6
4.2. Software de Memoria Transaccional . . . . . . . . . . . . . . . . . . . 8

5. Conclusiones 9

Bibliografı́a 10
The Clojure Way
holacaracola

1. Clojure
Clojure es un lenguaje de programación de propósito general dialecto de Lisp.
Hace un énfasis especial en el paradigma funcional, con el objetivo (entre otros) de
eliminar la complejidad asociada a la programación concurrente.
El enfoque de Clojure way reúne un conjunto de conceptos y caracterı́sticas para
cumplir con estos objetivos.

2. Conceptos y Caracterı́stica
2.1. Programación Funcional
Una caracterı́stica clave de Clojure es que es un lenguaje funcional. El paradig-
ma funcional se basa en que hay dos formas de diseñar un programa: Una forma es
hacerlo tan simple que obviamente no haya deficiencias, y la otra es hacerlo tan com-
plicado que no haya deficiencias obvias. Esto se asocia a la programación funcional
e imperativo respectivamente .
Los lenguajes imperativos realizan tareas complejas ejecutando un gran número
de instrucciones, que modifican secuencialmente un estado de programa hasta que
se logra un resultado deseado. Los lenguajes funcionales logran el mismo objetivo a
través de la composición de funciones anidadas, pasando el resultado de una función
como parámetro a la siguiente. Al componer y encadenar las llamadas de función,
junto con la recursión (una función que se llama a sı́ mismo), un programa funcional
puede expresar cualquier tarea posible que una computadora sea capaz de realizar.
Todo un programa puede ser visto como una sola función, definida en términos de
funciones más pequeñas.Dando una estructura de anidamiento y todos los datos
se manejan a través de parámetros de función y valores de retorno Come vemos
en la figura1 . Esto hace que todo el programa pueda ser entendido solo haciendo
un seguimiento de las funciones que lo componen sin tener que hacer un análisis
profundo del programa esta simplicidad hace el código transparente para la detección
de errores.

Figura 1: Estructura Programación Funcional

holacaracola Página 2
The Clojure Way
holacaracola

2.1.1. Programación puramente funcional


Las funciones puras son un concepto importante en la programación funcional,
como se muestra en la Figura 2. Dicho simplemente, una función pura es aquella que
no depende de nada más que de sus parámetros, y no hace otra cosa que devolver un
valor. Si una función lee desde cualquier lugar excepto sus parámetros, no es pura.
Si cambia algo en el estado del programa (conocido como un efecto secundario),
tampoco es puro.

Figura 2: Estructura Programación Funcional

Estado es cualquier dato que almacene el programa que posiblemente pueda ser
cambiado por más de una pieza de código. Es peligroso porque si el comportamiento
del código depende de una parte del estado, es imposible analizar lo que podrı́a hacer
sin tener en cuenta todos los valores posibles de ese estado, ası́ como cualquier otra
parte del programa que pudiera modificar ese estado. Este problema se magnifica
exponencialmente en programas paralelos, donde no siempre es fácil saber hasta qué
código de pedido se ejecutará. Es casi imposible predecir qué podrı́a ser un estado
dado.
Los efectos secundarios son cualquier cosa que una función hace cuando se eje-
cuta, además de simplemente devolver un valor. Si cambia el estado del programa,
escribe en un disco duro, o realiza cualquier tipo de IO, ha ejecutado un efecto
secundario.Por supuesto, los efectos secundarios son necesarios para un programa
para interactuar con cualquier cosa, incluido el usuario. Pero también hacen una
función mucho más difı́cil de entender y reutilizar en diferentes contextos.Por lo que
se consideran como males necesarios, y los programadores funcionales hacen todo lo
posible para utilizarlos lo menos posible.
Las funciones puras tienen una serie de ventajas:
Son notablemente fáciles de paralelizar. Dado que cada función es una unidad
distinta, encapsulada.

holacaracola Página 3
The Clojure Way
holacaracola

Las funciones puras conducen a un alto grado de encapsulación y reutilización


de código. Cada función es efectivamente una caja negra. Por lo tanto, entender
las entradas y las salidas, y usted entiendera la función. No hay necesidad de
conocer o preocuparse por la implementación.

Son más fáciles de razonar. En un programa puramente funcional, el árbol


de ejecución es muy sencillo. Al rastrear la estructura de llamada de función,
puede saber exactamente y por completo lo que el programa está haciendo.Para
entender un programa imperativo, con estado, no sólo necesita comprender el
código, sino todas las posibles permutaciones de estado que pueden existir en
cualquier momento.

2.1.2. Enfoque de Clojure


Clojure tiene dos maneras de mantener la pureza funcional tanto como sea po-
sible, mientras que todavı́a permite a un desarrollador hacer fácilmente todo lo que
necesitan.

Los efectos secundarios son explı́citos, y la excepción en lugar de la regla. Son


fáciles de agregar, cuando es necesario, pero se destacan del flujo natural de la
lengua. Esto asegura que los desarrolladores son precisamente conscientes de
cuándo y por qué ocurren y cuáles son sus efectos precisos.

Todo el estado del programa está contenido en estructuras seguras para hilos,
respaldadas por el inventario planificado de las caracterı́sticas de gestión de
concurrencia de Clojure. Esto asegura que con un mı́nimo absoluto de esfuerzo,
el estado del programa es siempre seguro y consistente. Las actualizaciones al
estado son explı́citas y atómicas y claramente identificables.

3. Inmutabilidad
Clojure alienta el estilo puramente funcional proporcionando un conjunto capaz
y de alto rendimiento de estructuras de datos inmutables.
Las estructuras de datos inmutables son, como su nombre indica, estructuras
de datos que no pueden cambiar. Se crean con un valor o contenido especı́fico, que
permanecen constantes durante todo el ciclo de vida del objeto.
Esto garantiza que el objeto se puede utilizar libremente en múltiples lugares,
desde múltiples hilos, sin temor a las condiciones de carrera ni a otros conflictos.
Si un objeto es de sólo lectura, siempre se puede leer de forma segura e inmediata
desde cualquier punto del programa.
Pero entonces ¿Qué pasa si la lógica del programa requiere que el valor de una
estructura de datos cambie? Clojure resuelve esto donde en lugar de modificar la
estructura de datos existente (causando todo tipo de efectos potencialmente dañados
para otras partes del programa que lo utilizan), la estructura se copia con los cambios
en su lugar vemos el la figura 3 y 4. El objeto antiguo permanece exactamente

holacaracola Página 4
The Clojure Way
holacaracola

como estaba, y otros hilos o porciones de código que funcionan actualmente en


él continuarán funcionando sin problemas, sin saber que hay una nueva versión.
Mientras tanto, el código que çambió.el objeto utiliza el nuevo objeto, idéntico al
antiguo excepto las modificaciones.
Esto suena como si pudiera ser extremadamente ineficiente, pero no lo es. De-
bido a que el objeto base es inmutable, el objeto ”modificado”puede compartir su
estructura excepto el punto real de cambio. El sistema sólo necesita almacenar el di-
ferencial, no una copia entera. Esta propiedad se llama persistencia: una estructura
de datos comparte memoria con la versión anterior de sı́ mismo. Hay una pequeña
sobrecarga de tiempo computacional al hacer un cambio, pero el uso de memoria
puede ser realmente menor. En muchos escenarios, los objetos pueden compartir
grandes partes de su estructura, aumentando la eficiencia. Las versiones antiguas de
los objetos se mantienen siempre y cuando se utilicen como parte de una versión
más reciente (o se haga referencia desde otro lugar) y se recojan silenciosamente
cuando ya no sean útiles.
Otro efecto interesante de objetos de datos inmutables y persistentes es que es
fácil mantener versiones anteriores y retroceder a través de ellos según sea necesario.

Figura 3: Inmutable Lista Enlazada

Figura 4: Inmutable Arbol Binario

holacaracola Página 5
The Clojure Way
holacaracola

4. Administración del estado


Casi todos los programas necesitan mantener un estado de trabajo de algún ti-
po. Siempre habrá una necesidad de un programa para almacenar hechos y datos,
y actualizarlos o manipularlos, de vez en cuando. Tradicionalmente, los lenguajes
de programación se ocupan de este problema al permitir que los programas tengan
acceso directo a la memoria a varios niveles de abstracción, la mayorı́a de los len-
guajes de programación se construyen alrededor del concepto de usar instrucciones
secuenciales para modificar una memoria compartida espacio. En este paradigma,
es enteramente de la responsabilidad del programador asegurar que la manipulación
y el acceso del estado se hace en una manera razonable que no cause problemas.
Con la llegada de programas multiproceso, la dificultad de administrar el esta-
do aumenta exponencialmente. No sólo debe un programador entender los posibles
estados del programa, sino que debe garantizar que el estado está protegido y modi-
ficado de una manera ordenada para evitar la corrupción de datos y condiciones de
carrera. Esto, a su vez, requiere complicadas polı́ticas de bloqueo, polı́ticas que no
hay forma de hacer cumplir. El incumplimiento de estas polı́ticas no causa problemas
evidentes, sino insidiosos errores que a menudo no surgen hasta que la aplicación
está bajo carga en un entorno de producción y puede ser casi imposible rastrear.
En general, habilitar la simultaneidad en un lenguaje tradicional requiere una
planificación cuidadosa, una comprensión muy completa de los caminos de ejecución
y la estructura del programa, y un cuidado extremo en la implementación.
Clojure ofrece una alternativa: una forma rápida y fácil para que los programa-
dores usen tanto estado como necesiten sin ningún esfuerzo extra para administrarlo,
incluso en un entorno altamente concurrente. Esto lo logra a través de su particular
filosofı́a de estado e identidad, sus objetos inmutables y la memoria transaccional
de software (STM).

4.1. Estado e identidad: Separar la Identidad del Estado


Para entender el tratamiento que Clojure hace del estado,consideremos desde un
punto de vista filosófico , lo que exactamente los términos .estado çambio”significan.
2

Tradicionalmente, la mayorı́a de los programadores dirı́an que el çambio”significa


que, dado un objeto o estructura de datos O, su valor en un momento dado llamado
T1 es diferente de aquel en un tiempo posterior, T2 . O sigue siendo O . Sin embargo,
algunas de sus propiedades o valores pueden ser diferentes, dependiendo de cuando
se le pregunte. La programación concurrente tradicional se ocupa de usar bloqueos
y semáforos para asegurar que las preguntas o las actualizaciones sobre las carac-
terı́sticas o los valores de O de diversos hilos ocurren de una manera ordenada que
no causen problemas.
Clojure ofrece un punto de vista diferente. En el mundo de Clojure, O en T1
y O en T2 no son ni conceptualmente el mismo objeto O, sino dos diferentes: O1
y O2 . Pueden tener similitudes en sus valores o propiedades o no, pero el punto
clave es que son diferentes objetos del sistema. ¿Qué es más, son inmutables, en
el sentido estricto de la programación funcional. Si se hace un çambio.adicional a

holacaracola Página 6
The Clojure Way
holacaracola

O2 , por ejemplo, no resulta un cambio en las propiedades o valores de O2 , sino la


creación de un objeto completamente nuevo, O3 . Un objeto en sı́ nunca cambia.
Para ayudar a obtener una comprensión de esto, considere el siguiente ejemplo.
En todos los lenguajes de programación (ası́ como el sentido común) el número 3
es el número 3, y nunca cualquier otro número. Si incremento 3, obtengo un nuevo
número, 4. No he cambiado el valor de 3, solo el valor de cualquier variable o registro
de almacenamiento lo contenı́a. La noción de cambiar el valor de .el número 3.a algo
distinto de 3 es absurdo, es difı́cil imaginar lo que podrı́a significar, y mucho menos
el estrago que podrı́a causar en el resto del programa que se basa en el valor de 3
siendo 3. Clojure simplemente toma esta noción intuitiva con respecto al valor, y
lo extiende a valores compuestos más grandes. Tomemos, por ejemplo, un conjunto,
digamos ”gente que me debe dinero”. Inicialmente, el conjunto podrı́a consistir en
S1 = Joe, Steve, Sarah. Pero luego recibı́ una carta de Steve, y tiene un cheque.
Finalmente ha pagado. La gente que me debe dinero ahora es S2 = Joe, Sarah.
Estos dos conjuntos no son los mismos por la definición de la igualdad establecida:
Uno contiene Steve, uno no lo hace. S1 no es igual a S2 más que como 3 = 4.
La mayorı́a de los lenguajes de programación manejarı́an el escenario anterior
por la mutación del valor del conjunto, S. En un escenario concurrente, esto podrı́a
causar todo tipo de problemas. Si un hilo itera a través de S mientras se elimina
Steve, inevitablemente lanzará un error, probablemente alguna variación de ”Índice
fuera de lı́mites”. Para compensar, el programador debe agregar manualmente un
sistema de bloqueos para asegurar que la iteración y la actualización se producen
secuencialmente, no al mismo tiempo, incluso si el código se ejecuta en subprocesos
diferentes.
Clojure tiene una filosofı́a diferente. La solución no es restringir el acceso a S a
operaciones secuenciales. El problema conceptual real es que, por un momento en el
tiempo mientras itera a través del conjunto, el programa asume que Joe, Sarah =
Joe, Steve, Sarah. Esto obviamente no es cierto, y es esta desconexión la que causa
el problema. Normalmente, es una expectativa razonable que un objeto sea igual a
sı́ mismo, pero no en un sistema concurrente que permita la mutación.
Utilizando sólo objetos inmutables, Clojure restaura la garantı́a de que los obje-
tos siempre se igualan a sı́ mismos. En el sistema de Clojure, S1 y S2 son diferentes
al programa, tal como son semántica y conceptualmente. Una operación que tiene
lugar en S1 no se ve afectada por la creación de S2 y terminará sin errores.
Obviamente hay alguna relación entre S1 y S2 . Desde una perspectiva humana,
ambos representan el mismo concepto, .el conjunto de personas que me deben di-
nero”. Clojure sigue esto introduciendo el concepto de identidad, a diferencia del
valor. Identidad, en Clojure, es una referencia nombrada que apunta a un objeto.
En el ejemplo anterior, habrı́a una identidad, por ejemplo, los deudores. En un mo-
mento dado, los deudores se refieren a S1 , y, en otro momento, se actualiza para
referirse a S2 . Pero esta actualización es atómica, y por lo tanto evita los efectos de
concurrencia como las condiciones de carrera. No hay punto en que el valor de los
deudores esté en un estado ambiguo, siempre se refiere a S1 o S2 , nunca a mitad de
camino. Siempre es seguro recuperar el valor actual de los deudores, y siempre es

holacaracola Página 7
The Clojure Way
holacaracola

seguro intercambiar su valor por uno nuevo. Esto es mostrado en la Figura 5.

Figura 5: Inmutable Arbol Binario

4.2. Software de Memoria Transaccional


Sin embargo, una visión adecuada del estado y la identidad no es la respuesta
completa. A menudo, en un programa los cambios a una identidad dependen del
estado de otro o un nuevo valor de una identidad necesita ser calculado basado en
el valor existente sin preocuparse de que otro hilo actualizará la identidad en medio
de la operación. Eso no causarı́a un error, como se discutió, pero podrı́a resultar en
los resultados del otro cálculo que se sobrescriben inapropiadamente.
Para acomodar estos escenarios, Clojure proporciona software de memoria tran-
saccional (STM). STM funciona proporcionando una capa de administración adicio-
nal entre el programa y la memoria de la computadora. Cada vez que un programa
necesita coordinar cambios en una o más identidades, envuelve el intercambio en
una transacción, similar en concepto a los utilizados para asegurar la integridad en
los sistemas de base de datos. Dentro de una transacción, el programador puede
realizar cálculos múltiples basados en identidades, asignarles nuevos valores y luego
confirmar los cambios. Desde la perspectiva del resto del programa, las transacciones
suceden de forma instantánea y atómica: Primero, las identidades tienen un valor
y luego otro, sin necesidad de preocuparse por los estados intermedios o los datos
inconsistentes. Si dos transacciones entran en conflicto, uno se ve obligado a rein-
tentar, comenzando de nuevo con los nuevos valores de las identidades involucradas.
Como vemos en la figura 6 donde dos las dos transacciones de escritura de la iz-
quierda ejecutadas en el mismo tiempo entran en conflicto al terminar una primera
y querer concluir haciendo la escritura esta es reiniciada con los nuevos valores ac-
tualizados.Durante todo esto una tercera de solo lectura pudo ejecutarse y terminar

holacaracola Página 8
The Clojure Way
holacaracola

sin problemas Esto sucede automáticamente; el programador sólo escribe el código,


la lógica de transacción es manejada automáticamente por el motor STM.

Figura 6: Transiciones en Conflicto

5. Conclusiones
Clojure way usa el enfoque funcional , inmutabilidad y gestión de los estados
para para dar una entorno de programación mucho mas fácil sobre todo en la
complejidad de la concurrencia solucionando el mismo entorno para de esta.

En enfoque te Software de Memoria Transaccional facilita mucho al progra-


mador pero el proceso de esta tiene un costo computacional adicianal pero es
justo este precio por la facilidad que brinda.

holacaracola Página 9
The Clojure Way
holacaracola

Bibliografı́a
[A] Paul Butcher Seven Concurrency Models in Seven Weeks1 (2014), pp. 85-113.

[Au] Michael Fogus ,Chris Houser The Joy of Clojure, 61, (2011), pp. 4-10.

[Al] N. Álvarez-Vázquez, P.A. Pérez y J. Rodrı́guez-Ruiz. Practical Clojure, pp.1-15


(2010)

[B] The Clojure Programming Language,. https://clojure.org

[B] Clojure STM,. https://sw1nn.com/blog/2012/04/11/clojure-stm-what-why-


how/

[Ba] Concurrency and Parallelism in Clojure,. http://clojure-


doc.org/articles/language/concurrencya ndp arallelism.htmlidentity − value −
separation − quot − on − state − and − identity − quot

holacaracola Página 10

S-ar putea să vă placă și