¿Es necesario entender lo que sucede a nivel de hardware para ser un buen programador?

24

Soy un programador autodidacta, en caso de que esta pregunta se responda en CS 101. Aprendí y usé muchos idiomas, principalmente para mi uso personal, pero ocasionalmente para cosas profesionales.

Parece que siempre me encuentro con el mismo muro cuando tengo problemas para programar. Por ejemplo, acabo de hacer una pregunta en otro foro sobre cómo manejar un puntero a matriz que fue devuelto por una función. Inicialmente estoy pensando que simplemente no conozco la técnica adecuada que los diseñadores de C ++ configuraron para manejar la situación. Pero de las respuestas y discusiones que siguen veo que realmente no entiendo lo que sucede cuando algo es "devuelto".

¿Qué nivel de comprensión del proceso de programación debe alcanzar un buen programador?

bev
fuente
3
Mi consejo: aprenda algo de ensamblaje x86 (DOS o de otro modo). Luego, aprenda a leer algunos de los resultados del ensamblador de algunas piezas pequeñas de código C. Haga preguntas si no entiende el resultado. Repetir. Esto lo obligará a comprender lo que está sucediendo a nivel de CPU
Earlz, el
Earlz: ¿Quiere decir que debería aprender a programar utilizando el conjunto de instrucciones x86? ¿Es ese el 'nivel de CPU'?
bev
Trabajo - gracias, eso fue divertido. De hecho, ha cometido algunos errores, solo para su información.
bev

Respuestas:

33

No. Nadie entiende lo que está sucediendo a nivel de hardware.

Los sistemas informáticos son como las cebollas: hay muchas capas y cada una depende de la capa que se encuentra debajo para obtener soporte. Si eres el tipo que trabaja en una de las capas externas, no deberías preocuparte demasiado por lo que sucede en el medio de la cebolla. Y eso es bueno, porque la mitad de la cebolla siempre está cambiando. Mientras la capa o capas que soportan su capa en particular sigan pareciendo y soporten su capa, está bien.

Pero entonces de nuevo...

Sí. Quiero decir, no necesitas entender lo que realmente está sucediendo dentro de la cebolla, pero ayuda mucho tener un modelo mental de cómo se ve el interior de una cebolla típica. Tal vez no sea la parte más profunda, donde tienes compuertas compuestas de transistores y tal, o la siguiente capa o dos, donde tienes microcódigo, un reloj, unidades de decodificación de instrucciones, etc. Sin embargo, las siguientes capas son donde Tengo registros, la pila y el montón. Estas son las capas más profundas en las que tiene mucha influencia sobre lo que sucede: el compilador traduce su código en instrucciones que se ejecutan a este nivel, y si lo desea, generalmente puede seguir estas instrucciones y descubrir qué está sucediendo "realmente".

Los programadores más experimentados tienen una versión de cuento de hadas de estas capas en su cabeza. Le ayudan a comprender de qué está hablando el compilador cuando le dice que hubo una "excepción de dirección no válida" o un "error de desbordamiento de pila" o algo así.

Si está interesado, lea un libro sobre arquitectura de computadoras. Ni siquiera tiene que ser un libro particularmente nuevo: las computadoras digitales han estado trabajando aproximadamente de la misma manera durante mucho tiempo. ¡Cuanto más aprenda sobre el interior de la cebolla, más se sorprenderá de que cualquiera de estas cosas funcione en absoluto! Aprender (aproximadamente) lo que sucede en las capas inferiores hace que la programación sea menos misteriosa y, de alguna manera, más mágica. Y realmente, más divertido.

Otra cosa que podría considerar son las cebollas integradas. Er, me refiero a los sistemas embebidos. Hay varias plataformas integradas que son bastante fáciles de usar: Arduino y BASIC Stamp son dos ejemplos. Estos son básicamente microprocesadores pequeños con muchas características incorporadas. Puede pensar en ellas como cebollas con menos capas que una PC de escritorio típica, por lo que es posible obtener una comprensión bastante completa de lo que está sucediendo en todo el sistema, desde el hardware hasta el software.

Caleb
fuente
2
Gracias. Esto básicamente responde a mi pregunta. Soy un EE que ha realizado diseño de registros, sumadores, multiplexores, etc. a nivel de chip (es decir, a nivel de transistor), por lo que obtengo el nivel más bajo (a menos que se trate de mecánica cuántica). También puedo usar los idiomas que conozco bastante bien. Solo tengo una gran brecha en el nivel medio (stack, heap), donde dices que el compilador hace su trabajo. Como, como lo expresó, quiero que mi experiencia de programación sea "menos misteriosa y ... más mágica". Parece que debería estudiar los niveles que aún desconozco.
bev
@bev: En ese caso, realmente deberías ver una plataforma como Arduino.
Caleb
Lamento ser aburrido, pero revisé Arduino, y realmente no puedo ver cómo usarlo me ayudaría a entender cómo un compilador trata los punteros y las matrices de manera diferente. ¿Qué no estoy viendo?
bev
@bev: Si solo quieres saber cómo se llaman las funciones, probablemente puedas pasar 30 minutos leyendo sobre eso y listo. Si desea tener una mejor idea de cómo funciona todo junto, será más fácil con un sistema pequeño. Es la mejor manera de tener toda la cebolla en la cabeza a la vez. AVR, la familia de chips en la que se basa Arduino, es un sistema agradable, fácil de usar y de uso general con un conjunto de instrucciones lo suficientemente pequeño como para aprender sin demasiados problemas.
Caleb
Ah ok. La página de inicio es un poco turbia en ese aspecto de sus productos. Lo miraré de nuevo.
bev
10

No estás hablando del nivel de hardware, estás hablando de lo que realmente hace el compilador con lo que le dices que haga.

Sin duda, necesita este nivel de comprensión para descubrir qué salió mal cuando no es obvio, especialmente cuando se trata de una situación de pisoteo de memoria.

Loren Pechtel
fuente
Loren - Si! Gracias por la simple verdad. Ahora necesito encontrar la mejor manera de aprender qué hacen los compiladores de c ++ con sus tipos de datos. Por cierto, como EE, sé que no es literalmente el nivel de hardware. Simplemente no sabía cómo lo llaman ustedes, geeks de CS. (Todavía no es así. ¿Nivel de compilador?)
bev
Por cierto - memoria pisadas?
bev
@Bev: Acabas de demostrar mi punto aquí: si ni siquiera sabes qué es un pisotón de memoria, tendrás un tiempo terrible para encontrar un error debido a uno. Un pisotón de memoria es cuando algo escribe en una ubicación que se supone que no debe y borra (pisotea) lo que sea que esté allí. Si tienes suerte, lo que golpeaste fue inmediatamente vital y al menos explota. Si no tienes suerte, el programa simplemente continúa con algunos agujeros en sus datos.
Loren Pechtel
gracias por la aclaración. También me muestra cuánto no sé, ya que hasta donde sé, simplemente escribo en el montón o en la pila, sin un control más preciso.
bev
@Bev: El problema surge cuando escribes en un lugar que no crees que estás escribiendo. Tienes algo en la pila y le haces un puntero. Dejas la rutina: el elemento desaparece, el puntero no. Ahora, ¿qué pasa cuando le escribes a ese puntero? O tiene una serie de 100 elementos: ¿qué sucede cuando escribe en el elemento # 200?
Loren Pechtel
6

Understanding Program Memory! = Comprensión del hardware

Comprender la jerarquía de memoria == Comprender el hardware


Para responder a su pregunta genérica: depende. No está de más entender el hardware, pero comprenderlo no ayudará en todos los casos.

Según su ejemplo, solo necesita comprender más sobre cómo se divide la memoria y cómo se organiza cuando ejecuta un programa. Comprender el hardware no lo ayudará a este respecto, porque la memoria (como es visible para un programa) ni siquiera representa realmente el hardware gracias a la magia de la memoria virtual.

Si tuviera curiosidad acerca de los problemas de rendimiento en función del orden en el que accede a la memoria, AHORA se beneficiaría de la comprensión del hardware, la jerarquía de memoria, errores de caché, fallas de página y toda la gloriosa y maravillosa bondad que proviene del hardware.

Riwalk
fuente
Stargazer: todavía no estoy en el punto en el que pueda preocuparme por problemas de rendimiento. Espero pronto. Gracias por tus comentarios.
bev
5

Si no decide aprender un poco de ensamblador, probablemente debería aprender algo así como 6502 ensamblador en un Commodore 64 (emulado, por supuesto), o 68000 en un Amiga.

Puedes hacerte una idea del Commodore 64 aquí ...

http://thepiratebay.org/torrent/4609238/Tag3-Saal2-Slot16_00--ID2874-the_ultimate_commodore_64_talk-Main

El clásico libro de todo lo que necesitas saber es el que se describe aquí ...

http://reprog.wordpress.com/2010/03/12/programming-books-part-3-programming-the-commodore-64/

Probablemente pueda encontrar un escaneo PDF si mira a su alrededor.

OMI, 6502 es más fácil que Z80, y 68000 es más fácil que 8086: más conjuntos de instrucciones regulares, etc.

Pero la CPU es solo un aspecto del hardware. Además, una CPU moderna es una bestia enormemente diferente, y hace cosas que son transparentes incluso desde el punto de vista de los compiladores, como presentar un espacio de direcciones virtual.

Una ventaja particular del 6502 en el C64 es que no solo la CPU es simple, sino que también hay hardware muy sencillo de piratear. Solía ​​divertirme mucho jugando con el chip de música SID.

Entonces, probablemente sea un ejercicio que valga la pena si no le dedica demasiado tiempo. Aprendí 6502 ensamblador como mi segundo idioma cuando tenía unos 14 años, justo después de Commodore Basic. Pero sobre todo está obteniendo ese modelo de trabajo muy simple para que pueda agregarle ideas más sofisticadas con un mínimo de malentendidos.

Algunas cosas útiles que puedes aprender trabajando en ensamblador ...

  • Cómo funcionan los registros de CPU.
  • Cómo funciona el direccionamiento de memoria, incluida la indirección.
  • Cómo funciona la pila de CPU.
  • Cómo funciona la lógica bit a bit.
  • Cómo controla la CPU los dispositivos de E / S.
  • Cómo interrumpe el trabajo.

Una razón particular que recomendaría es tener una mejor intuición de la forma en que los pasos simples funcionan de manera totalmente determinista, mecánica y absoluta, sin inteligencia ni sentido común. Básicamente, acostumbrarse al modelo de ejecución imperativo en su forma más pura y obstinadamente ignorante.

Sin embargo, lo útil que es saber la mayoría de esas cosas ahora es una pregunta difícil.

Una cosa que no aprenderá es cómo jugar bien con una jerarquía de memoria. Esas máquinas antiguas en su mayoría tenían un modelo de memoria simple sin capas de caché y sin memoria virtual. Tampoco aprenderá mucho sobre la concurrencia: ciertamente fueron formas de manejar eso, pero en su mayoría significaron interrupciones. No tenía que preocuparse por mutexes, etc.

A veces, un modelo mental de cómo estas cosas una vez trabajado, o de cómo funciona la ensamblador, incluso puede inducir a error. Por ejemplo, pensar en un puntero C como una dirección puede conducir a problemas de comportamiento indefinidos. El puntero de CA normalmente se implementa como un entero que contiene una dirección, pero no hay garantía de que sea estrictamente cierto. Por ejemplo, en algunas plataformas extrañas, diferentes punteros pueden apuntar a diferentes espacios de direcciones. Esto se vuelve importante cuando quieres hacer aritmética o lógica bit a bit con dos punteros.

A menos que tenga una de esas plataformas extrañas, es posible que no piense que le importa, pero en la actualidad los compiladores son cada vez más propensos a explotar comportamientos indefinidos para la optimización.

Por lo tanto, un modelo mental de la arquitectura del sistema puede ser útil, pero sigue siendo importante codificar según las especificaciones del lenguaje, no según un modelo hipotético que su lenguaje y plataforma pueden no respetar.

Finalmente, muchas cosas útiles del modelo mental provienen de tener una idea de cómo los compiladores generan código, y la generación de código para lenguajes modernos es muy diferente de los compiladores bastante triviales disponibles en ese momento.

Este es un libro mío favorito para eso ...

http://dickgrune.com/Books/MCD_1st_Edition/

Junto con el material sobre análisis y AST, etc., cubre la generación de código para una variedad de paradigmas de lenguaje: imperativo, OOP, funcional, lógico, paralelo y distribuido, y también para la gestión de la memoria. Si desea saber cómo funcionan las llamadas a métodos polimórficos sin atascarse en los detalles del conjunto de instrucciones de la CPU, un libro como este es su amigo, y pronto saldrá una nueva edición.

Steve314
fuente
Steve - wow Estoy casi sin palabras con la integridad y el enfoque de su respuesta a mi pregunta. Muchas gracias por tomarse el tiempo para escribir todo esto. Definitivamente tomaré tus sugerencias.
bev
1
Sugeriría que el ensamblador PDP-11 es un poco más agradable de aprender que todos los demás mencionados. Lo que todos los demás enseñan son las limitaciones forzadas por recursos de hardware más limitados, y / o por diseño y previsión de hardware más limitados. Algo así como una de la familia 8051 demasiado común enseña cuán extraño puede llegar a ser el modelo de programación en un hardware tan limitado (donde entra en juego la mención de Steve de diferentes espacios de direcciones, por ejemplo).
Greg A. Woods,
@ Greg - Nunca tuve la oportunidad de jugar con un PDP-11, me temo. Ni un 8051: hice un trabajo incrustado por un tiempo, pero eso fue usar un chip de la familia 8096. Sin embargo, solo eché un vistazo aquí , interesante. Escuché sobre la arquitectura de Harvard antes de algún tiempo, pero no tenía idea de que algo como esto fuera muy popular y todavía esté en uso.
Steve314
4

Hace veinte años era importante, pero no tanto ahora: hay muchas más capas de abstracción entre el software y el hardware moderno.

Es útil saber cosas como necesitar múltiples subprocesos para aprovechar múltiples núcleos o que usar más memoria de la que existe en el sistema es algo malo, pero más allá de eso realmente no lo necesita a menos que sea su trabajo escribir esas abstracciones capas.

El resto de su pregunta sugiere que puede estar más preocupado con el compilador que con el hardware, que es un poco diferente. Puede encontrar casos en los que es importante, pero estos tienden a ser triviales (la recursión infinita no funciona muy bien) o el tipo de casos extremos en los que puede sentirse bien al resolverlo, pero probablemente nunca se encuentre con el mismo problema. otra vez.

Tom Clarkson
fuente
Sí, tienes razón, estoy más preocupado por el compilador. Además, gracias por su sugerencia sobre múltiples hilos, múltiples núcleos, etc. Simplemente se ha ido a mi archivo de notas de toLearn.
bev
@bev multithreading es fácil de aprender, simplemente no lo hagas a menos que realmente tengas que hacerlo e incluso no lo hagas. más problemas de lo que vale en mi experiencia.
Skeith
@Skeith: gracias por la sugerencia. Lo tendré en cuenta.
bev
4

Es de gran ayuda conocer y comprender la abstracción presentada por el hardware, y un poco de la idea general sobre cómo se crea esa ilusión, pero tratar de entender realmente cómo funciona realmente el hardware moderno es una gran cantidad de trabajo del cual usted ' Es probable que vea solo un retorno mínimo.

Si perdonas una distracción menor: esto me recuerda algo que noté hace unos años. Hace décadas (hasta fines de la década de 1970, más o menos), la mayoría de las personas pensaban que las computadoras eran mágicas, apenas afectadas por las leyes de la física, capaces de todo tipo de cosas que tenían poco sentido real, etc. En ese momento, pasé una buena cantidad de tiempo intentando (en su mayoría sin éxito) convencer a la gente de que no, que no eran mágicos. Eran máquinas realmente bastante ordinarias que hacían un número limitado de cosas de manera muy rápida y confiable, pero por lo demás eran extremadamente mundanas.

Hoy en día, la visión de la mayoría de las personas sobre las computadoras ha cambiado. Ahora son bastante comunes, hasta el punto de que algunas personas muy comunes tienen una comprensión práctica de ellos. Solo por ejemplo, hace un tiempo, mientras estaba cenando, vi / escuché a un mesero y una mesera en su descanso discutiendo lo que debería obtener en su nueva computadora. El consejo que estaba dando era completamente razonable y realista.

Sin embargo, mi visión de las computadoras también ha cambiado. He ido a Hot Chips, y antes de eso, el Foro de Microprocesadores se remonta a mediados de la década de 1990 más o menos. Probablemente sé más sobre el hardware de microprocesador que al menos el 99% de los programadores, y sabiendo lo que hago, diré esto: ya no son comunes. Ellos hacen casi rompen las leyes de la física. He realizado muchas pruebas de bajo nivel y puedo decirlo con certeza: superar la ilusión creada por la CPU y mostrar cómo funciona realmente el hardware a menudo es increíblemente difícil. Desearía poder publicar una imagen de una de nuestras configuraciones con una computadora enterrada bajo cables de no menos de 4 analizadores lógicos solo para medir adecuadamente uno aspecto de cómo funciona el almacenamiento en caché en una CPU moderna (sin mencionar una programación realmente fastidiosa para garantizar que lo que medimos era exactamente lo que estaba haciendo la CPU, y nada más).

Jerry Coffin
fuente
Jerry, gracias por tus comentarios. Al ser un EE, me siento más cómodo con el nivel de transistor que algunos de los niveles de abstracción más altos. Realmente me pregunto qué necesito saber para ser un buen programador de C ++.
bev
Esa foto suena interesante. ¿Por qué no puedes publicarlo?
Mason Wheeler
@Bev: Realmente no necesitas saber nada a nivel de transistor para ser un buen programador. Esas abstracciones están ahí por una razón, y casi siempre puedes considerar que cualquier cosa en un nivel de abstracción por debajo del código / ensamblaje de la máquina es completamente irrelevante y simplemente asumes que funciona.
Mason Wheeler
@MasonWheeler: Lo llevé a donde solía trabajar, pero como ya no trabajo allí, obtener acceso a él probablemente sería un poco más difícil (probablemente no imposible; renuncié en buenos términos, pero aún así. ..)
Jerry Coffin
1

Los diferentes idiomas funcionan en diferentes niveles de abstracción del hardware. C y C ++ son de muy bajo nivel. Los lenguajes de script, por otro lado, requieren que sepa menos sobre los detalles subyacentes.

Sin embargo, todavía diría que en todos los casos, cuanto más sepa, mejor será un programador. Parte de la programación es poder hacer malabarismos con múltiples niveles de abstracción al mismo tiempo.

Si está programando en C ++, debe comprender bastante bien cómo funciona una CPU moderna, al menos en el nivel de abstracción en el que funciona el compilador. (También están sucediendo cosas dentro de la CPU que son transparentes para el compilador).

Scott Whitlock
fuente
Scott: por "una comprensión bastante buena de cómo funciona una CPU moderna ...", ¿te refieres a cómo funciona la lógica digital (por ejemplo, cómo funcionan los mapas karnaugh, las tablas de verdad y las puertas AND / OR / NOR / XOR)? ¿O quiere decir qué recursos utiliza directamente el compilador (es decir, los registros)?
bev
Saber más es bueno. Sin embargo, el verdadero truco es saber qué tipo de "más" le dará el mayor rendimiento a su inversión. Conocer los tiempos de las instrucciones, por ejemplo, no será de mucha utilidad cuando sea casi imposible predecir qué instrucciones usará su compilador. Aprender a usar un perfilador probablemente dará una relación costo / beneficio mucho mejor.
Steve314
1
@bev - No, no creo que necesites bajar al nivel de la puerta. Si acaba de conocer la arquitectura básica (memoria, bus, CPU), cómo carga una instrucción, la ejecuta, almacena el resultado, etc., probablemente esté bien. También debe comprender cómo el compilador distribuye el espacio de memoria de un programa, incluida la forma en que utiliza la pila y el montón.
Scott Whitlock
@ScottWhitlock - Gracias, este es el tipo de recomendaciones específicas que estaba buscando.
bev
0

Me gustaría agregar un punto sobre el diseño general de lenguajes de nivel superior como C.

En general, creo que es seguro decir que dichos lenguajes pueden verse como la implementación de una máquina abstracta, y de hecho así es como el propio Dennis Ritchie ha descrito cómo funciona C y cómo el diseño particular de la máquina abstracta de C lo ha convertido en un lenguaje más portátil. Como tal, tener cierta comprensión de la arquitectura de la computadora y el funcionamiento a nivel de máquina, puede ser extremadamente útil para comprender también la máquina abstracta de un lenguaje.

La Portabilidad en papel de DMR de los Programas C y el Sistema UNIX es la primera que recuerdo para discutir el modelo de máquina (abstracto) para C.

Creo que el artículo de DMR sobre la historia y el desarrollo de C también es extremadamente útil para mostrar cómo el hardware real afecta el diseño del lenguaje, y quizás también sea un ejemplo del diseño de lenguaje de programación inicial: El desarrollo del lenguaje C

Greg A. Woods
fuente
Como eres nuevo aquí, pareces pensar que este es un foro, ciertamente no lo es. Sus respuestas a una pregunta no deben ser un punto que agregue, que deben relegarse a los comentarios, y la respuesta debe intentar ser una respuesta integral directamente a la pregunta. Dicho esto, está haciendo un buen punto y esto es valioso en la información del tema, tal vez si pudiera poner algunas líneas en esa respuesta, la pregunta directamente junto con esta explicación sería genial. Buena información que estás compartiendo aquí. ¡Bienvenido a los programadores!
Jimmy Hoffa
los comentarios no están versionados y no son permanentes, por lo que son inútiles para agregar a un conjunto de respuestas. La mayoría de los carteles también son propensos a ignorar el uso de comentarios para actualizar sus respuestas, y la mayoría de las respuestas no están etiquetadas como respuestas "wiki de la comunidad" y, por lo tanto, no pueden ser editadas por otros de tal manera que se mantenga alguna atribución a los contribuyentes posteriores. . Además, esta pregunta en particular ha comenzado una verdadera discusión, y nos guste o no, así es como funcionan algunas de estas cosas. Intentar forzar cada contribución en un molde es una falla importante del concepto de intercambio de pila.
Greg A. Woods
y, por cierto, en realidad respondí, aunque implícitamente, la única pregunta verdadera del OP: uno debe tener una comprensión suficiente del hardware para poder modelar la máquina abstracta en el núcleo del diseño de un lenguaje.
Greg A. Woods el