Simon Peyton Jones mismo reconoce que razonar sobre el desempeño en Haskell es difícil debido a la semántica no estricta.
Todavía tengo que escribir un proyecto importante en Haskell, así que me pregunto: ¿puedo razonar sobre el rendimiento solo al comienzo de un proyecto (al elegir estructuras de datos básicas y biblioteca de E / S) y cuando surja un problema, lidiar con el perfilador?
Para decirlo de otra manera, ¿es posible (es decir, no demasiado doloroso) posponer el manejo del rendimiento cuando tiene problemas de rendimiento, o tiene que aprender a predecir cómo GHC ejecutará su código (por ejemplo: infiera lo que decidirá el analizador de rigor) )?
performance
haskell
Simon Bergot
fuente
fuente
Respuestas:
Las otras respuestas brindan amplios consejos sobre el razonamiento del desempeño. Esta respuesta aborda específicamente la semántica no estricta.
Si bien la pereza hace que sea más difícil razonar sobre el rendimiento, no es tan complicado como podría pensar. Aunque la pereza es bastante útil en algunas situaciones, la mayoría de las veces se usa un lenguaje perezoso de la misma manera que se usaría un lenguaje estricto. En consecuencia, el razonamiento de rendimiento para lenguajes estrictos se puede aplicar (con algunos ajustes) a lenguajes perezosos.
En términos de complejidad de tiempo, la evaluación entusiasta hace estrictamente más trabajo que la evaluación perezosa. Ambas estrategias producen el mismo resultado en la mayoría de los casos. (Más precisamente, si la evaluación entusiasta no se encuentra con ningún error, produce el mismo resultado que la evaluación diferida). Por lo tanto, para razonar sobre la complejidad temporal de un programa Haskell, puede pretender que evalúa con entusiasmo. En aquellas situaciones poco frecuentes donde la pereza es importante, esta estimación será demasiado alta y debería revisarse a la baja.
Si bien la evaluación diferida le brinda una menor complejidad de tiempo que una evaluación entusiasta, a veces le brinda una mayor complejidad espacial, es decir, fugas de espacio. Se puede corregir una mayor complejidad espacial agregando anotaciones de rigor para hacer que un programa se ejecute con más entusiasmo. Las herramientas de perfilado son bastante buenas para rastrear la causa de las fugas de espacio. Clasificaría esto como depuración de corrección o depuración de rendimiento, dependiendo de la gravedad.
fuente
In terms of time complexity, eager evaluation does strictly more work than lazy evaluation.
¿En qué basas esa afirmación? Suponiendo que la evaluación ansiosa terminará en el mismo punto que la evaluación perezosa (es decir, no entrar en una evaluación perezosa de secuencias infinitas y cosas así) un algoritmo de generación ansiosa siempre será tan rápido o más rápido (es decir, hacer menos trabajo) que un algoritmo perezoso porque no requiere la sobrecarga de llamadas repetidas en una rutina de generador.all even [1..1e10]
tanto una versión estricta como una perezosaall
. El compilador también tiene más margen para elegir el orden de evaluación en un lenguaje como Haskell con cosas como la fusión en bucle.Optimice las cosas grandes antes de codificar, y las pequeñas cosas cuando haya terminado.
Por ejemplo, antes de comenzar a codificar, debe pensar en lo siguiente:
...y así.
Luego, cuando casi haya terminado con su código, piense en las pequeñas cosas como qué función incorporada es más rápida, ¿debería reescribir esa área de código para hacerlo más eficiente, etc.
Esto es cierto para cualquier idioma, y realmente depende del tipo de software que esté escribiendo. Haskell es un lenguaje de propósito general, por lo que probablemente (corríjame si me equivoco) no está haciendo nada que deba ser extremadamente rápido. Si es así, debe usar un lenguaje de nivel inferior. Si la velocidad es un problema, pero no lo suficiente como para usar un lenguaje de bajo nivel, entonces debe optimizar su rendimiento en base a lo anterior.
Por supuesto, todo el mundo hace las cosas de manera diferente, por lo que si su experiencia personal le hace pensar que debería hacerlo de manera diferente según su situación, entonces probablemente debería hacerlo.
fuente
Me gustaría agregar a la respuesta de Dynamic:
Cuando se dé cuenta más adelante en el desarrollo de los cuellos de botella que tiene su código, puede ser realmente doloroso refactorizar todo el proyecto. Si su código está bien estructurado, los cuellos de botella son más fáciles de encontrar y optimizar / corregir.
fuente