O que é design orientado a dados?


156

Eu estava lendo este artigo , e esse cara continua falando sobre como todos podem se beneficiar muito da mistura de design orientado a dados com OOP. Ele não mostra nenhum exemplo de código, no entanto.

Eu pesquisei isso no Google e não consegui encontrar nenhuma informação real sobre o que é isso, muito menos quaisquer exemplos de código. Alguém conhece este termo e pode dar um exemplo? Talvez essa seja uma palavra diferente para outra coisa?


7
Esse artigo na desenvolvedor do jogo está agora disponível em fácil de ler em forma de blog: gamesfromwithin.com/data-oriented-design
Edmundito

58
Vocês já pesquisaram alguma coisa no Google, encontraram uma boa pergunta SO direcionada e perceberam que foi você quem a fez anos atrás?
ryeguy

1
Aqui está um conteúdo agregado de DOD na web
legends2k

14
@ryeguy, eu tive uma pergunta, pesquisei no Google, encontrei uma boa pergunta para SO e percebi que respondi anos atrás.
Michael Deardeuff

4
Eu pesquisei algo no Google e encontrei uma boa pergunta para SO e adivinhem? Não foi nem eu que pediu nem quem respondeu :)
Nadjib Mami

Respostas:


288

Primeiro de tudo, não confunda isso com design orientado a dados.

Meu entendimento do Design Orientado a Dados é que se trata de organizar seus dados para um processamento eficiente. Especialmente com relação a falhas de cache, por outro lado, o Data Driven Design é sobre permitir que os dados controlem grande parte do comportamento de seus programas (descrito muito bem pela resposta de Andrew Keith ).

Digamos que você tenha objetos de bola em seu aplicativo com propriedades como cor, raio, bounciness, posição etc.

Abordagem Orientada a Objetos

No OOP, você descreveria bolas como esta:

class Ball {
  Point  position;
  Color  color;
  double radius;

  void draw();
};

E então você criaria uma coleção de bolas como esta:

vector<Ball> balls;

Abordagem Orientada a Dados

No Design Orientado a Dados, no entanto, é mais provável que você escreva o código assim:

class Balls {
  vector<Point>  position;
  vector<Color>  color;
  vector<double> radius;

  void draw();
};

Como você pode ver, não há mais uma unidade representando uma bola. Objetos de bola existem apenas implicitamente.

Isso pode ter muitas vantagens, em termos de desempenho. Normalmente, queremos fazer operações em muitas bolas ao mesmo tempo. O hardware geralmente deseja que grandes pedaços contínuos de memória operem com eficiência.

Em segundo lugar, você pode executar operações que afetam apenas parte das propriedades de uma bola. Por exemplo, se você combinar as cores de todas as bolas de várias maneiras, deseja que seu cache contenha apenas informações de cores. No entanto, quando todas as propriedades da bola estiverem armazenadas em uma unidade, você puxará todas as outras propriedades da bola também. Mesmo que você não precise deles.

Exemplo de uso de cache

Digamos que cada bola ocupa 64 bytes e um ponto ocupa 4 bytes. Um slot de cache ocupa, digamos, 64 bytes também. Se eu quiser atualizar a posição de 10 bolas, preciso extrair 10 * 64 = 640 bytes de memória para o cache e obter 10 erros de cache. Se, no entanto, eu puder trabalhar as posições das bolas como unidades separadas, isso levará apenas 4 * 10 = 40 bytes. Isso se encaixa em uma busca de cache. Assim, temos apenas 1 falta de cache para atualizar todas as 10 bolas. Esses números são arbitrários - presumo que um bloco de cache seja maior.

Mas ilustra como o layout da memória pode ter um efeito severo nos acertos do cache e, portanto, no desempenho. Isso só aumentará em importância à medida que a diferença entre a velocidade da CPU e da RAM aumentar.

Como organizar a memória

No meu exemplo de bola, simplifiquei bastante o problema, porque geralmente para qualquer aplicativo normal você provavelmente acessará várias variáveis ​​juntas. Por exemplo, posição e raio provavelmente serão usados ​​juntos com frequência. Então sua estrutura deve ser:

class Body {
  Point  position;
  double radius;
};

class Balls {
  vector<Body>  bodies;
  vector<Color>  color;

  void draw();
};

O motivo para você fazer isso é que, se os dados usados ​​juntos forem colocados em matrizes separadas, existe o risco de que eles concorram pelos mesmos slots no cache. Assim, carregar um jogará fora o outro.

Portanto, comparadas à programação orientada a objetos, as classes que você acaba fazendo não estão relacionadas às entidades em seu modelo mental do problema. Como os dados são agrupados com base no uso de dados, você nem sempre terá nomes sensíveis para dar suas aulas no Design Orientado a Dados.

Relação com bancos de dados relacionais

O pensamento por trás do Design Orientado a Dados é muito parecido com o que você pensa sobre bancos de dados relacionais. A otimização de um banco de dados relacional também pode envolver o uso mais eficiente do cache, embora, nesse caso, o cache não seja o cache da CPU, mas as páginas na memória. Um bom designer de banco de dados também provavelmente dividirá os dados acessados ​​com pouca frequência em uma tabela separada, em vez de criar uma tabela com grande número de colunas, onde apenas algumas das colunas foram usadas. Ele também pode optar por desnormalizar algumas das tabelas para que os dados não precisem ser acessados ​​de vários locais no disco. Assim como no Design Orientado a Dados, essas escolhas são feitas observando quais são os padrões de acesso a dados e onde está o gargalo de desempenho.


4
Obrigado por isso, você explicou muito bem.
Ryeguy

4
bem dito; Só tenho uma pergunta. Digamos que temos uma estrutura struct balls {vector<vec3> pos; vector<vec3> velocity;}, não atualizando a posição de cada bola na verdade debulha o cache, pois você se move entre o vetor de velocidade e o vetor de posição (sim, máquinas modernas e linhas de cache e tudo isso, isso é também apenas uma ilustração)?
falstro 3/08/10

14
Poderia. Mas lembre-se de que todo o array pos não será inserido de cada vez. Apenas uma linha de cache e possível alguma pré-busca. Da mesma forma com a velocidade. Para que eles joguem o lixo na lixo, cada pedaço correspondente de pos e vetor precisa mapear para o mesmo cache. É claro que isso pode acontecer, e é por isso que a recomendação é reunir variáveis ​​que são usadas juntas em uma estrutura. Assim, por exemplo, velocidade e pos estariam em um vetor, enquanto a cor estaria em outro vetor.
Erik Engheim 17/08/10

1
@roe Você deve agrupar propriedades que são acessadas juntas. Entre propriedades, não deve haver nenhuma dependência. Então essa estrutura seria melhor struct balls { vector<color> colors; vector<body> bodies; /* contains position and velocity */ }.
Danijar

2
@danijar Atualizei a explicação com suas sugestões. Eu poderia ter dito muito mais sobre isso, mas isso realmente se transformará em um artigo.
Erik Engheim

18

Mike Acton fez uma palestra pública sobre design orientado a dados recentemente:

Meu resumo básico seria: se você deseja desempenho, pense no fluxo de dados, encontre a camada de armazenamento com maior probabilidade de se ferrar com você e otimize bastante. Mike está se concentrando nas falhas de cache L2, porque está realizando em tempo real, mas imagino que o mesmo se aplique aos bancos de dados (leitura de disco) e até à Web (solicitações HTTP). É uma maneira útil de programar sistemas, eu acho.

Observe que isso não o impede de pensar em algoritmos e complexidade de tempo, apenas concentra sua atenção em descobrir o tipo de operação mais caro que você deve direcionar com suas habilidades loucas de CS.


14

Eu só quero ressaltar que Noel está falando especificamente sobre algumas das necessidades específicas que enfrentamos no desenvolvimento de jogos. Suponho que outros setores que estão realizando simulação em tempo real se beneficiariam disso, mas é improvável que seja uma técnica que mostre melhorias visíveis em aplicativos de negócios em geral. Essa configuração é para garantir que todo o último desempenho seja extraído do hardware subjacente.


Acordado. Algumas outras áreas em que o design orientado a dados é significativo são: hardware e firmware para dispositivos de alta largura de banda (por exemplo, rede ou armazenamento); computação científica em larga escala (por exemplo, simulação climática, dobragem de proteínas), processamento de sinais (por exemplo, áudio, imagem, vídeo), compactação de dados. Eles se enquadram na "Ciência e Engenharia da Computação", que às vezes é oferecida como especialização separada da Ciência da Computação mais típica.
Rjong

-3

Um design orientado a dados é um design no qual a lógica do aplicativo é constituída de conjuntos de dados, em vez de algoritmos procedimentais. Por exemplo

abordagem processual.

int animation; // this value is the animation index

if(animation == 0)
   PerformMoveForward();
else if(animation == 1)
  PerformMoveBack();
.... // etc

abordagem de design de dados

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();

Projetos de dados como esse promovem o uso de dados para criar a lógica do aplicativo. É mais fácil de gerenciar, especialmente em jogos de vídeo que podem ter milhares de caminhos lógicos baseados em animação ou em algum outro fator.


14
Na verdade, isso não está correto. Você está confundindo design orientado a dados com design orientado a dados. Fiz a mesma coisa até ler o artigo de Noel e perceber que ele estava falando sobre algo completamente diferente.
Erik Engheim

12
Além disso, o índice não é uma palavra. Há "índice" e "índices" e alguns até toleram "índices", mas "índice" nunca está certo.
Baxissimo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.