¿Cuáles son algunas instancias en la programación donde un tiempo de cálculo más rápido no siempre es mejor?

Desde una perspectiva de Ciencia e Ingeniería Computacional, la pérdida de generalidad es una preocupación importante.

Puedo escribir un código de elementos finitos increíblemente rápido en Matlab (en paridad con buenos códigos C ++) que hace el trabajo en quizás una docena de líneas, pero solo funciona en volúmenes rectangulares, y tengo que ingresar manualmente todas las condiciones de carga. Eso funciona para una gran cantidad de problemas con los que tengo que trabajar, pero a cambio sacrifica toda generalidad. Es posible que no tenga problemas con ese enfoque actualmente, pero tan pronto como intente volver a aplicar este código, será un problema importante.

Dentro de la comunidad de la ciencia computacional, hay decenas de diferentes métodos y aproximaciones para resolver el mismo conjunto de problemas. A veces, se puede preferir un método menos eficiente si es más general, porque puede volver a aplicar rápidamente su código a futuros problemas de interés.


Una consideración adicional cuando se trabaja en programas científicos y de ingeniería es la precisión y la estabilidad de un método numérico.

Uno de los aspectos más críticos de este campo de programación es el error de discretización. Al resolver problemas matemáticamente continuos en un sistema que representa las cosas discretamente, siempre introduce algún tipo de error. Según el método que utilice para resolver estos problemas, sus errores pueden acumularse en el transcurso de la solución, y su respuesta final puede ser inexacta. Para soluciones que se repiten muchas veces, esto puede hacer que su inexactitud sea teóricamente infinita; A esto le llamamos divergencia de comportamiento.

Algunos métodos son más costosos, pero garantizan que tendrá una solución precisa al final. Otros métodos no son necesariamente más costosos o más precisos, pero tienen un procedimiento adicional de minimización de errores para garantizar la convergencia.

Para problemas que se han caracterizado como sensibles a estos problemas, puede ser necesario un método más lento para obtener una solución confiable.


Al final, mirar un fragmento de código como una consideración de arriba / abajo más rápido o más lento se desmorona cuando comienzas a trabajar en problemas de ciencias computacionales. Hay muchos caminos hacia una solución, y son más o menos precisos, más o menos estables y más o menos generales.

Deben tomarse decisiones sobre cuánto rendimiento sacrifica para generar un programa confiable y robusto.

Espero que mi opinión sobre esta pregunta tenga sentido y que le sea útil.

En los primeros días de la informática en línea (1970, 1980), los departamentos de TI a menudo se veían afectados por los usuarios comerciales que se quejaban de los tiempos de respuesta. Nadie quiso escuchar ninguna explicación de por qué los tiempos de respuesta fueron los mismos.

A veces, las empresas incluso compraron actualizaciones más potentes y muy costosas para tratar de resolver las quejas.

Aún así, los usuarios no querían escuchar que la gran mayoría del tiempo de respuesta estaba en la red , no en la CPU. Por lo tanto, hacer que la CPU sea más rápida no ayudó en absoluto. Y, como se dijo, era muy costoso.

Por lo tanto, los departamentos de TI más astutos se dieron cuenta (con las herramientas de medición apropiadas) de que lo que los usuarios estaban realmente interesados ​​era la variabilidad en los tiempos de respuesta. La solución fue generar retrasos en las respuestas para que, sin importar la carga de la CPU, el tiempo de respuesta en la pantalla del usuario fuera siempre el mismo.

Entonces, para responder a su pregunta, debe elegir la solución que brinda a la mayoría de los usuarios el mismo tiempo de respuesta con mayor frecuencia. Si la solución de Bob varía de 0,5 segundos a 1,5 segundos sin que el usuario sepa por qué, eso es malo. Si los 2 segundos de Billy son consistentes, elija esa solución.

NOTA AL PIE para aficionados: tanto la pregunta como esta respuesta discuten solo el tiempo transcurrido de la acción. No se ha dicho nada sobre los efectos que tienen las dos soluciones en la carga de la CPU y la carga de E / S, que son consideraciones vitales en la informática real.

Desde el punto de vista puramente UX, 2 segundos frente a 0,5 segundos, aunque definitivamente es una diferencia notable, no es realmente tan impactante debido a los tiempos de reacción humanos típicos, a menos que esa operación se repita varias veces seguidas. Por lo tanto, si la solución de Billy es más fácil de mantener, Billy gana, a pesar de que la solución de Bob es más rápida.

Hay algo que se ignora mucho en la comunidad de principiantes, es decir, el código se lee con mucha más frecuencia de lo que se escribe . Además, la velocidad generalmente importa mucho menos de lo que piensas, tu código pasa la mayor parte del tiempo esperando la entrada . Por lo tanto, a menos que estemos hablando de una mejora significativa en el orden de magnitud, la solución que es más fácil de comprender (¡y, en consecuencia, desarrollar más!) Es a menudo superior.

En el ámbito del hashing de contraseñas, un algoritmo de hashing rápido se considera malo.

La razón es que una ralentización de 5x cuando se necesita calcular el hash cada vez que un usuario inicia sesión es soportable (por ejemplo, 100ms adicionales de espera para una solicitud de red pueden no molestar mucho a un usuario) pero una ralentización de 5x descarrilará mucho intentos de descifrar hash de delincuentes que obtuvieron hash de contraseña. Obligar a un delincuente a pasar 5 días en lugar de 1 día para descifrar contraseñas significa dar a los sitios pirateados tiempo para restablecer todas las contraseñas de los usuarios y notificar a los usuarios afectados para que puedan restablecer las contraseñas que podrían reutilizar en otros sitios.

Referencia: Cómo almacenar de forma segura una contraseña

Además de las razones convincentes ofrecidas por el usuario de Quora, permítanme agregar:

  • La solución más rápida se basa en características específicas del conjunto de problemas que podrían no ser ciertas en una declaración más generalizada del problema, a la que algún día podría aplicarse este código. (“¡Pero jefe, funcionó en todos nuestros conjuntos de datos de prueba! Resulta que los datos de los clientes se comportan peor de lo que esperábamos”).
  • La solución más rápida es mucho más difícil de entender que la solución más lenta. (“Explícame nuevamente lo que estás haciendo aquí en la línea 33? Todavía no lo entiendo”)
  • No se puede demostrar que la solución más rápida sea correcta, pero la solución más lenta sí.
  • La solución más rápida introduce al proyecto dependencias de construcción adicionales u otros problemas de mantenimiento que significan que las horas de mano de obra para mantenerlo exceden su valor marginal para el proyecto. (“Sí, lo sé, este algoritmo es más rápido, pero lo escribiste en Kotlin y el resto de nuestro proyecto está en Ruby y si incluimos esto significa que tenemos que mantener una etapa de construcción separada solo para este código. Reescríbalo en Ruby o deshazte de él “)

Evaluación de solicitudes de autenticación. Dos ejemplos:

  • Si se proporciona un nombre de usuario incorrecto, es posible devolver la falla rápidamente sin evaluar la corrección de la contraseña. Esta es una mala idea, ya que permite a los atacantes identificar rápidamente nombres de usuario válidos por fuerza bruta. Como mínimo, debe agregarse un retraso apropiado. Idealmente, se debe agregar un retraso a todas las solicitudes de autenticación, exitosas o no, para que no se puedan distinguir por tiempo.
  • En caso de que falle el estrangulamiento automático, un algoritmo de evaluación de contraseña relativamente lento limita la exposición a ataques que se basan en evaluaciones repetidas (ya sea fuerza bruta o no).

Estos todavía pueden ser rápidos en una escala de tiempo humana.

En caso de que esté proporcionando un servicio en línea, la respuesta es: Experiencia del usuario (en algunos casos).

Por ejemplo, imagine que algunos usuarios están pagando por un servicio a través de Internet y esta transacción se completa en unos pocos milisegundos, esto definitivamente haría que sus usuarios se sintieran dudosos … Sin embargo, darle algo de tiempo probablemente hará que el usuario sienta que hay algo de trabajo. pasando en el fondo.

Seguro. Hay algoritmos que son rápidos, pero dan respuestas aproximadas. Es posible que necesite algo numérico más preciso y esté dispuesto a tolerar que sea más lento. Por ejemplo, GPS: si solo intento descifrar mi código postal desde la ubicación del GPS, no necesito nada muy preciso. Pero si estoy escribiendo un código para ayudar a aterrizar un avión en condiciones climáticas adversas, ¡quiero terminar en la pista, no a 2 millas de distancia en un centro comercial!

En una aplicación web, quizás la solución más rápida aplazó la actualización de la base de datos hasta una fecha posterior. Esto dejaría la base de datos en un estado inconsistente. Algunos sistemas pueden tolerar eso cuando, por ejemplo, solo se reconcilia una vez al día. Pero si está ejecutando una aplicación web en vivo, necesitaría actualizar la base de datos de inmediato para que el estado actual sea correcto.

Estos son ejemplos hipotéticos. En la vida real, las diferencias reales entre ingenieros competentes que ya han trabajado para optimizar su código pueden ser menores.

  1. La solución más rápida requiere bibliotecas propietarias que aumenten los costos de licencia.
  2. Una solución más rápida requiere mayor potencia / energía en un entorno donde esos recursos están limitados.
  3. La solución más rápida agrega una complejidad de código significativa pero no acelera la ejecución en la ruta crítica (la solución de 2 segundos mueve este código fuera de la ruta crítica, por lo tanto, una mayor optimización no afecta el tiempo de solución).
  4. El código más rápido no “rompe nada” ahora, sino que se basa en características no portátiles que podrían romperse en el futuro.

Un tiempo de cálculo más rápido no siempre es mejor, a veces es lo mismo .

¿Tienes una copia de seguridad con carreras durante la noche y toma 6 horas? Si agrega 2 segundos o 0.5 segundos, a nadie le importa, es lo mismo.

Dependiendo de lo que esté haciendo, la velocidad puede no ser su máxima prioridad, puede favorecer todo tipo de otras cosas como:

Fiabilidad, uso de memoria, interfaz de usuario atractiva, código más legible, o tal vez porque la solución lleva más tiempo, los usuarios permanecen en una página más tiempo y ven más anuncios.

La velocidad es a veces, pero rara vez es una preocupación en la programación del mundo real.

  1. Claridad: la solución de Bob es más arcana, difícil de entender y difícil de verificar en la revisión de código
  2. Mantenibilidad: la solución de Bob es difícil de alterar a medida que cambian los supuestos detrás del problema. O tal vez la solución de Bob es una red enmarañada de bucles y declaraciones recurrentes. O tal vez comprender y mantener la solución de Bob requiere saber algo que solo Bob sabe (por ejemplo, lenguajes de programación menos conocidos como Cobol o APL). O tal vez Bob sea despedido pronto por no documentar su trabajo en un vano intento de asegurar un empleo continuo.
  3. Escalabilidad: la solución de Billy es realmente más rápida que la de Bob cuando hay más tráfico web, o con el paso del tiempo y el conjunto de datos consultado o utilizado para el cálculo se vuelve muy grande.
  4. Seguridad: la solución de Bob deja vacantes para los hackers
  5. Recursos: la solución de Bob requiere mucha más memoria o espacio para datos.

Una razón obvia sería la legibilidad. Si la solución de características se escribiera en un ensamblaje ilegible, como un lenguaje, que se ejecuta rápidamente, pero que nadie más puede leer, esa solución no debería aceptarse. Si la solución de 2 segundos (que sigue siendo una mejora) es clara e intuitiva, esa solución sería la que tomaría.

Cualquier razón por la cual la solución de Billy fue más fácil o más barata de trabajar. Si la solución de Billy fue:

  • más fácil de probar
  • más fácil de probar correcto
  • más fácil de modificar o ampliar
  • más fácil de interactuar con
  • más fácil de mantener o portar
  • más rápido de escribir

Si la aceleración de Billy fue “suficientemente rápida”, entonces entran en juego todos los demás factores económicos.

Dondequiera que esté involucrado un humano, como un sitio web.

Hacemos clic en el botón, estamos encantados con una respuesta en un segundo.

Eso es miles de millones de ciclos de CPU disponibles

Además, donde se puede usar la escala horizontal. El servidor A puede estar ocupado, por lo que en lugar de hacerlo más rápido, enrutamos la siguiente solicitud al servidor B

Un caso clásico es el hash de contraseñas. Intencionalmente ralentizamos este proceso mediante el uso de una gran cantidad de rondas de hash para proteger las tiendas de credenciales contra los ataques del diccionario, haciéndolos extremadamente caros de realizar.

La solución de Billy podría usar un almacenamiento en caché de RAM excesivo, en lugar de realizar cálculos / tareas pieza por pieza como lo hace Bob, lo que significa que Bob trabajará en una gama más amplia de hardware.

Billy’s puede usar todos los núcleos intencionalmente, pero hace que la computadora host se retrase horriblemente durante 500 ms, mientras que Bob solo usa un núcleo y permite que las tareas en segundo plano se ejecuten sin obstáculos.

La solución de Billy podría implicar bloquear totalmente una base de datos durante 500 ms para evitar condiciones de carrera con otros programas, mientras que Bob utiliza el bloqueo semántico para permitir que otras tareas funcionen simultáneamente.

Los dos grandes son (a) el uso de memoria (sí, probablemente pueda usar la paginación, pero eso ralentiza las cosas mucho más), y (b) lo fácil que será leer en el futuro (para depuración y extensibilidad).

Si aún no se han construido, el tiempo de desarrollo y la escalabilidad también son posibles consideraciones.

Puede causar problemas de experiencia del usuario. Ninguno de los dos rompe nada, pero si su cliente bloquea el javascript, podría optar por una solución más lenta y sin bloqueo que no haga que la GUI se congele.

Si el trabajo es algo así como manejar una solicitud, el código de Bob podría ser más rápido para una sola solicitud, pero si su solución depende en gran medida de la sincronización del acceso a recursos compartidos, entonces la solución de Billy podría ser más rápida para manejar millones de solicitudes.