haskell - una - ¿Se puede duplicar un procesador para mejorar el rendimiento de la memoria?
se puede mejorar el procesador de una laptop (3)
Uno de mis problemas con la evaluación perezosa en Haskell es la dificultad de razonar sobre el uso de la memoria. Creo que la capacidad de duplicar un procesador me haría esto mucho más fácil. Aquí hay un ejemplo.
Vamos a crear una lista realmente grande:
let xs = [1..10000000]
Ahora, vamos a crear una mala función:
bad = do
print $ foldl1'' (+) xs
print $ length xs
Sin optimizaciones, esto consume unas pocas docenas de MB de RAM. El recolector de basura no puede desasignar xs durante el pliegue porque será necesario para calcular la longitud más adelante.
¿Es posible volver a implementar esta función algo como esto:
good = do
(xs1,xs2) <- copyThunk xs
print $ foldl1'' (+) xs1
print $ length xs2
Ahora, xs1 y xs2 representarían el mismo valor, pero también serían independientes entre sí en la memoria, por lo que el recolector de basura puede desasignarse durante el pliegue, lo que evita el desperdicio de memoria. (Creo que esto aumentaría ligeramente el costo computacional, sin embargo?)
Obviamente, en este ejemplo trivial, refactorizar el código podría resolver fácilmente este problema, pero parece que no siempre es obvio cómo refactorizar. O a veces la refactorización reduciría enormemente la claridad del código.
Convierte xs
en una función. Esto puede ser feo, pero funciona, porque impide compartir:
let xs () = [1..1000000]
good = do
print $ foldl1'' (+) (xs ())
print $ length (xs ())
Interesante pregunta. No sé cómo implementar copyThunk
. Pero hay algo más que puedes hacer (perdón si ya sabías esto):
xsFunction :: () -> [Int]
xsFunction = const [1..10000000]
better = do
print $ foldl1'' (+) $ xsFunction ()
print $ length $ xsFunction ()
Aquí definitivamente no pondrá la expresión xsFunction ()
en un procesador, se calculará dos veces, por lo que no hará que la memoria se hinche.
Un interesante seguimiento de esto es:
- ¿Se puede implementar
copyThunk
algunacopyThunk
? - ¿Debería un programador de haskell estar perdiendo el tiempo con estas optimizaciones de nivel relativamente bajo? ¿No podemos asumir que podemos ser más astutos que nosotros?
Me preguntaba lo mismo hace un tiempo y creé una implementación prototípica de una función de duplicación de procesador de este tipo. Puede leer sobre el resultado en mi preprint „ dup - Deshacer explícito en haskell ” y ver el código en http://darcs.nomeata.de/ghc-dup . Desafortunadamente, el documento no fue aceptado para el Simposio de Haskell ni para el Taller de Implementadores de Haskell este año.
Que yo sepa, no hay una solución para el problema del mundo real; solo soluciones de trabajo frágiles como el truco de parámetros de la unidad que podría romperse debido a una u otra optimización del compilador.