0votos

STM vs Bloqueos en Clojure

por josejuan hace 6 años

Tomado directamente de la documentación, arroja un rendimiento pésimo (diría yo) ¿porqué?.

A raíz de la fructífera conversación surgida en el desafío de "La tela de araña", se propone comparar las estrategias STM vs Bloqueos más fondo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
;; tomado de: http://clojure.org/concurrent_programming 
 
(import '(java.util.concurrent Executors)) 
  
(defn test-stm [nitems nthreads niters] 
  (let [refs  (map ref (repeat nitems 0)) 
        pool  (Executors/newFixedThreadPool nthreads) 
        tasks (map (fn [t] 
                      (fn [] 
                        (dotimes [n niters] 
                          (dosync 
                            (doseq [r refs] 
                              (alter r + 1 t)))))) 
                   (range nthreads))] 
    (doseq [future (.invokeAll pool tasks)] 
      (.get future)) 
    (.shutdown pool) 
    (map deref refs))) 
  
(test-stm 1000 6 100000) 
 
(shutdown-agents) 
 
 
;============================================== 
; en un AMD 6 cores 
 
$ time -f "t: %E, cpu: %P, mem: %M" clj swap.clj  
t: 9:23.82, cpu: 145%, mem: 703968 
 
el mismo proceso en C# usando bloqueos 
 
$ time -f "t: %E, cpu: %P, mem: %M" mono ./counting.exe  
Sum node values: 600000000 
t: 0:09.31, cpu: 415%, mem: 8164 
10 comentarios
0votos

Escrito por jneira hace 6 años

Curioso el uso de cpu en el caso de clojure... has probado a usar pmap en lugar de map?
0votos

Escrito por josejuan hace 6 años

No hay diferencia significativa.

También me fijé que apenas paraleliza.

La verdad, no entiendo porqué pone ese código ahí, ¡es el primer enlace cuando en google buscas "clojure concurrency"! ¿acaso la gente no vamos a pensar que es la forma correcta de hacerlo?

Por mi parte aquí queda (al menos de momento) mi incursión a Clojure; mucho mejor sabor de boca me dejó Scala.

;)
0votos

Escrito por jneira hace 6 años

Por ser justos, por lo menos en cuanto al tema de la concurrencia..¿usastela STM que viene incluida en el framework "oficial" akka de scala? ¿o al menos algun mecanismo abstracto de control de concurrencia que te evite usar locks manuales?
Digo, para ver si su rendimiento es mejor que la de clojure o no.
0votos

Escrito por josejuan hace 6 años

He posteado constantemente información detallada (todo lo que he podido), realizado diversas pruebas, profundizado en el desafío de las arañas, creado otro desafío específico, etc... si no he sido justo, ten por seguro que será por mi incapacidad, no por mi parcialidad. ;)

Así, animo a los clojureros a resolver los desafíos de forma adecuada.

¡Ánimo!
0votos

Escrito por jneira hace 6 años

No hombre, no me referia a tus pruebas con clojure sino a la comparacion (general) con scala que hacias: habria que hacer una prueba similar con scala para ver si su STM deja "mejor sabor de boca" o no.
Con clojure tambien puedes usar locks manuales y aventuro que su rendimiento no estara tan alejado de la version de java de tu codigo en c#.
0votos

Escrito por josejuan hace 6 años

similar con scala

ya lo se (akka scala), pero me gustaría hacer otras cosas :P

con clojure también

(¿el día de la marmota?) incluso con STM, haciéndolo como deba hacerse el rendimiento no debería ser peor que el doble o triple o incluso 10 (actualmente 60), pero no tengo tanta curiosidad para ver cómo


Me ha gusto mucho la incursión, pero este desafío ha finalizado para mí.
0votos

Escrito por jneira hace 6 años

Estaba ejecutando tu codigo y me ha llamado la atencion que el resultado de la suma de los nodos no coincide entre la version de clojure y c#
user> (apply + (time (test-stm 1000 6 10))) 
"Elapsed time: 328.405231 msecs"
210000
user> (apply + (time (test-stm 1000 6 100))) 
"Elapsed time: 1841.761591 msecs"
2100000
user> (apply + (time (test-stm 1000 6 1000))) 
"Elapsed time: 18810.170053 msecs"
21000000

No tengo paciencia para esperar pero parece evidente que:
user> (apply + (time (test-stm 1000 6 100000))) 
"Elapsed time: 1881000.170053 msecs"
2100000000

Sin embargo la version en c# saca: 600000000
2.100.000.000 vs 600.000.000

¿El bench con clojure no ha sido pues con el codigo (test-stm 1000 6 100000) que tienes copiado? ¿El codigo no es el mismo? ¿No lo estoy ejecutando igual?
0votos

Escrito por josejuan hace 6 años

Yo he dado por supuesto que el código de Clojure era correcto, reconozco que intenté obtener esa suma, pero al no cuadrarme los valores, pensé que era fallo mío.

Si nos ceñimos a su enunciado:

"In this example a vector of Refs containing integers is created (refs), then a set of threads are set up (pool) to run a number of iterations of incrementing every Ref (tasks)."

Tenemos que nthreads añadiendo niters a nitems da, de toda la vida, nthreads * niters * nitems

Así, 1.000 * 6 * 100.000 = 600.000.000, que es lo que devuelve mi código en C#.

¿Entonces resulta que su código ni siquiera funciona bien? XD XD XD

(espero que no, vamos a revisar a ver...)
0votos

Escrito por josejuan hace 6 años

En su propia ejecución (url otra vez), su test es:

(test-stm 10 10 10000)
-> (550000 550000 550000 550000 550000 550000 550000 550000 550000 550000)


claro, ya lo tengo, en su definición dicen que lo incrementan ¡pero no cuanto! (y por tanto hemos asumido [como es normal] que en uno).

Lo que hace es:

(alter r + 1 t)


Luego es n*(n+1)/2 es decir si es 10, tenemos 10 11 / 2 = 55.

pero esto no cambia nada, puesto que la diferencia entre "inc" y "add" en una dirección de memoria pienso que podemos despreciarla (o desde luego no es el motivo por el que hay una diferencia de 60 en tiempo de ejecución).
0votos

Escrito por josejuan hace 6 años

Para quedarnos tranquilos, cambiando:

public void Inc(int k) {Interlocked.Add(ref n, k);}


y

Enumerable.Range(1, nthreads)


y

i.Inc(q);


el resultado es el mismo (bueno mejor, porque he metido la mejora de drabor).

$ time -f "t: %E, cpu: %P, mem: %M" mono ./counting.exe
Sum node values: 2100000000
t: 0:03.20, cpu: 255%, mem: 7880

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.