data oriented design - ¿Qué es el diseño orientado a datos?
data-oriented-design (4)
Estaba leyendo este artículo , y este tipo sigue hablando de cómo todos pueden beneficiarse enormemente al mezclar en diseño orientado a datos con OOP. Sin embargo, no muestra ningún ejemplo de código.
Busqué en Google esto y no pude encontrar ninguna información real sobre qué es esto, y mucho menos sobre ejemplos de código. ¿Alguien está familiarizado con este término y puede dar un ejemplo? ¿Es esta quizás una palabra diferente para otra cosa?
En primer lugar, no confunda esto con el diseño impulsado por datos.
Mi comprensión del diseño orientado a datos es que se trata de organizar sus datos para un procesamiento eficiente. Especialmente con respecto a errores de caché, etc. El diseño impulsado por datos, por otro lado, se trata de permitir que los datos controlen gran parte del comportamiento de los programas (muy bien descrito por la respuesta de Andrew Keith ).
Digamos que tiene objetos de bola en su aplicación con propiedades tales como color, radio, rebote, posición, etc.
Enfoque orientado a objetos
En OOP, describirías bolas como esta:
class Ball {
Point position;
Color color;
double radius;
void draw();
};
Y luego crearías una colección de bolas como esta:
vector<Ball> balls;
Enfoque orientado a los datos
Sin embargo, en Diseño orientado a datos es más probable que escriba el código de esta manera:
class Balls {
vector<Point> position;
vector<Color> color;
vector<double> radius;
void draw();
};
Como puede ver, ya no hay una sola unidad que represente una Bola. Los objetos de bola solo existen implícitamente.
Esto puede tener muchas ventajas en cuanto al rendimiento. Por lo general, queremos hacer operaciones en muchas bolas al mismo tiempo. El hardware generalmente quiere grandes fragmentos continuos de memoria para funcionar de manera eficiente.
En segundo lugar, puede realizar operaciones que afecten solo a parte de las propiedades de una bola. Por ejemplo, si combina los colores de todas las bolas de varias maneras, entonces quiere que su caché solo contenga información de color. Sin embargo, cuando todas las propiedades de la pelota se almacenan en una unidad, también se obtendrán todas las demás propiedades de una pelota. Aunque no los necesites.
Ejemplo de uso de caché
Digamos que una pelota, cada bola ocupa 64 bytes y un Punto toma 4 bytes. Una ranura de caché toma, digamos, 64 bytes también. Si quiero actualizar la posición de 10 bolas, tengo que introducir 10 * 64 = 640 bytes de memoria en la memoria caché y obtener 10 errores de caché. Sin embargo, si puedo trabajar las posiciones de las bolas como unidades separadas, eso solo tomará 4 * 10 = 40 bytes. Eso encaja en una búsqueda de caché. Por lo tanto, solo obtenemos 1 error de caché para actualizar todas las 10 bolas. Estos números son arbitrarios Supongo que un bloque de caché es más grande.
Pero ilustra cómo el diseño de la memoria puede tener graves impactos en la memoria caché de efectos y, por lo tanto, rendimiento. Esto solo aumentará en importancia a medida que la diferencia entre la CPU y la velocidad de la RAM se amplíe.
Cómo distribuir la memoria
En mi ejemplo de pelota, simplifiqué mucho el problema, porque generalmente para cualquier aplicación normal es probable que accedas a múltiples variables juntas. Por ejemplo, la posición y el radio probablemente se utilizarán juntos con frecuencia. Entonces tu estructura debería ser:
class Body {
Point position;
double radius;
};
class Balls {
vector<Body> bodies;
vector<Color> color;
void draw();
};
La razón por la que debe hacer esto es que si los datos usados juntos se colocan en matrices separadas, existe el riesgo de que compitan por los mismos espacios en la memoria caché. Por lo tanto, cargar uno arrojará al otro.
Entonces, en comparación con la programación orientada a objetos, las clases que terminas haciendo no están relacionadas con las entidades en tu modelo mental del problema. Dado que los datos se agrupan según el uso de datos, no siempre tendrá nombres razonables para dar sus clases en Diseño Orientado a los Datos.
Relación con las bases de datos relacionales
El pensamiento detrás del Diseño Orientado a los Datos es muy similar a cómo piensas acerca de las bases de datos relacionales. La optimización de una base de datos relacional también puede implicar el uso de la memoria caché más eficiente, aunque en este caso, la memoria caché no es el caché de la CPU poner páginas en la memoria. Un buen diseñador de bases de datos también probablemente dividirá los datos a los que se accede con poca frecuencia en una tabla separada en lugar de crear una tabla con un gran número de columnas, donde solo se utilizaron algunas de las columnas. También podría optar por desnormalizar algunas de las tablas para que no se tenga que acceder a los datos desde múltiples ubicaciones en el disco. Al igual que con el Diseño orientado a datos, estas elecciones se realizan al observar cuáles son los patrones de acceso a los datos y dónde se encuentra el cuello de botella de rendimiento.
Mike Acton dio una charla pública sobre el diseño orientado a datos recientemente:
Mi resumen básico sería: si quieres rendimiento, piensa en el flujo de datos, encuentra la capa de almacenamiento que es más probable que te arruine y optimiza para ello . Mike se está centrando en errores de caché L2, porque lo está haciendo en tiempo real, pero imagino que lo mismo se aplica a las bases de datos (lecturas de disco) e incluso a la Web (solicitudes HTTP). Es una forma útil de hacer la programación de sistemas, creo.
Tenga en cuenta que no le absolverá de pensar en los algoritmos y la complejidad del tiempo, solo enfoca su atención en descubrir el tipo de operación más costosa que debe apuntar con sus locas habilidades de CS.
Solo quiero señalar que Noel está hablando específicamente sobre algunas de las necesidades específicas que enfrentamos en el desarrollo de juegos. Supongo que otros sectores que están haciendo simulación suave en tiempo real se beneficiarían de esto, pero es poco probable que sea una técnica que muestre una mejora notable en las aplicaciones comerciales generales. Esta configuración es para garantizar que hasta el último bit de rendimiento se elimine del hardware subyacente.
Un diseño orientado a datos es un diseño en el que la lógica de la aplicación se construye a partir de conjuntos de datos, en lugar de algoritmos de procedimiento. Por ejemplo
enfoque de procedimiento.
int animation; // this value is the animation index
if(animation == 0)
PerformMoveForward();
else if(animation == 1)
PerformMoveBack();
.... // etc
enfoque de diseño de datos
typedef struct
{
int Index;
void (*Perform)();
}AnimationIndice;
// build my animation dictionary
AnimationIndice AnimationIndices[] =
{
{ 0,PerformMoveForward }
{ 1,PerformMoveBack }
}
// when its time to run, i use my dictionary to find my logic
int animation; // this value is the animation index
AnimationIndices[animation].Perform();
Los diseños de datos como este promueven el uso de datos para construir la lógica de la aplicación. Es más fácil de administrar, especialmente en videojuegos, que pueden tener miles de rutas lógicas basadas en animación o algún otro factor.