Ferdy escribió:Y sobre lo de kek_500: Realmente creo que estás confundiéndote mucho. Entiendo que te refieres al principio de localidad de la información relacionada con los conceptos de caché y memoria virtual. Bien, aquí hay dos cosas: datos y código. La parte de código es interesante que esté cerca pero, siendo prácticos, está todo muy cerca. El código de un software es interrumpido por el planificador para ejecutar otras tareas muchas veces por segundo así que esto no es un gran problema. La localidad de los datos es una cosa completamente distinta. Aquí si que es importante que los datos estén bien colocados; pero el cómo estén colocados no depende ni del paradigma ni, en principio, del lenguaje. Es todo, o casi todo, tarea del diseño/implementación.
Como veo que haces algunas preguntas, te voy a contestar a las que pueda:
[...]
- ferdy
Lamento no haber podido contestar antes. Ya de vuelta a la rutina, vuelvo a dar la brasa. Primero un ejemplo concreto: el lenguaje de programación java.
Como bien mencionas los programas constan de una serie de segmentos. Me interesan principalmente dos: datos y código. Quién controla todo es el sistema operativo (aunque no entiendo muy bien a que venía la actuación del mismo en tu comentario...). Bien, ¿qué es lo que ve entonces el SO cuando ejecuta una aplicación de este tipo?
Java es un lenguaje en parte compilado (a bytecode), parte interpretado por la JVM. Para el SO, el código es la JVM y los datos nuestros propios programas. ¿Esto se encuentra relativamente cerca (los datos)? No. Si por ejemplo "almacenamos" una base de datos ( los índices que precisemos ), por poner un ejemplo distinto, ¿estará realmente cerca el punto de entrada de mi aplicación a estos datos?¿O a la siguiente rutina que queramos invocar? Pues probablemente no.
¿En C pueden ocurrir estas cosas? No puesto que diferenciamos entre datos y código.
Ahora antes de que me digáis nada, me diréis: "Java ha sido pensado para ser multiplataforma. Existe más orientación a objetos fuera, es un paradigma no un lenguaje concreto". Perfecto, entiendo esa preocupación. Pongamos un segundo caso C++, como referente de POO, compilado, con todas las características de estos lenguajes: polimorfismo, herencia múltiple, etc, aunque podéis escoger el que más os guste.
C++ efectivamente realiza esa distinción entre código y datos. Por un lado tenemos código, por otro los datos, y como bien apuntas ferdy el código está relativamente cerca. ¡OJO! Nadie nos asegura que todas las páginas estén en memoria. ¿Acaso sabemos cómo están implementados los SO's? De linux algo de información podemos tener pero del resto... Sin embargo, pensemos que todos ellos usan esa filosofía de "memoria no usada, memoria desperdiciada".
Mi aplicación en C++ probablemente tenga diversas clases que representen mi minimundo (con seguridad más que probablemente). Una llamada a una función, desencadenará en llamadas a otras clases distintas seguramente.
Un ejemplo sencillo, perdonad si no me he dignado en hacer un diagrama UML en condiciones, o no he representado las composiciones adecuadamente:
...........................Dibujo
...........................======
.........................+.void.dibujar();
....................../......................\...
..................../..........................\.............................................................
................../..............................\...........................................................
................/..................................\.........................................................
Figuras.Geométricas..................Título
.............^..................................======
..............|..................................-.String.texto;
..............|..................................-.
int.TAMANO_FUENTE;
..............|..................................-.
int.COLOR_FUENTE;
.................................................+.void.dibujar();
..........Círculo.....................................................Coordenada
..........====.................................................==========
.....-.int.radio;.....................................................-.int.x;
.....-.Coordenada.centro;...................................-.int.y;
....-----------------------------
.....+.void.dibujar();
Pensemos que operaciones realiza la función dibujar de la clase "Dibujo". Tenemos un objeto del tipo dibujo que consta de un círculo y de un título, e invoco a dibujar sobre la primera clase:
- Accedemos al objeto círculo. Dado que el objeto no se almacena en la propia clase dibujo, sino que únicamente tenemos un puntero, vamos a buscar nuestra instancia. ¡Aquí no tenemos certeza de que esté en memoria! Peor de los casos (y probable): Fallo de página. Si a lo que intentamos acceder son a variables estáticas de una clase,
tendremos que cargar la información relativa a esa clase. Y en el peor de los casos si el código de esa clase no está cargado peor suerte aún. Tras estas operaciones a bajo nivel, ya estamos listos para ejecutar nuestro método.
Podemos proceder igual con el título.
¿Y si lo único que necesito es mi variable TAMANO_FUENTE porque decido ignorar el color?
¿No he tirado mi tiempo yendo a buscar información que no quería? Porque de estos campos no se realiza una copia en cada objeto, son comunes a todos las instancias y he necesitado cargar en memoria la página con la información de esa clase. Podríamos crear una copia de TAMANO_FUENTE en cada instancia, como solución chapucera. Pero, ¿qué ocurre si esa variable estática es la base de datos antes mencionada? Es inviable.
¿Qué ocurre en la programación estructurada? Evidentemente el problema de acceder a un dato que no tenemos en memoria puede ocurrir (queremos acceder al círculo). Pero todos esos fallos por acceder a los datos de una clase en particular no se producen. Nuevamente vuelvo al caso de mi interfaz gráfica pese a que algunos insistan en que puedo confundir cosas. Si tengo una ventana cualquiera, es bastante probable que tenga ciertas constantes definidas sobre como los objetos se distribuyen en pantalla. Si en un determinado momento debo repintar la memoria tengo que acceder a las clases involucradas en dicha acción (posibles botones, tablas, o widget en general), obtener los datos de sus respectivas clases, además de conseguir tales objetos.
No se si te habré convencido ferdy, la verdad creo que mi idea no te hacía demasiada gracia. Una última mención:
"Aquí si que es importante que los datos estén bien colocados; pero el cómo estén colocados no depende ni del paradigma ni, en principio, del lenguaje. Es todo, o casi todo, tarea del diseño/implementación."
El cómo estén colocados si que depende o más bien el qué se coloca, pues no estará en el mismo punto los datos de un objeto concreto, que el de la propia clase (que es un ente nuevo que aparece con la programación orientada a objetos). De hecho heurísticamente (y te diría que casi empíricamente) se puede comprobar que la pila de llamadas/accesos a clases en un lenguaje OO es mayor que la pila de llamadas a funciones en la programación estructurada. Hablando hoy en clase sobre este tema, me han dicho que hay investigaciones al respecto de este asunto, que en algún momento libre que tenga no tendría mayores problemas en buscar.