¿Objeto de matrices o matriz de objetos?

13

Estoy haciendo un juego de simulación de gestión, algo parecido a Roller Coaster Tycoon. Quiero saber cuál es la mejor manera de estructurar mis objetos mundiales para maximizar el rendimiento.

Digamos que tengo 5,000 personas en mi juego que podría:

Haga un objeto y almacénelos en una matriz así;

class person() {
    this.x = 0;
    this.y = 0;
    this.thirst = 15;
    this.hunger = 15;
    // etc.. add methods:
    public findPath(int destX, int destY) {
    // and so on
    }

    people = new person[5000];

for (int = 0; i < 5000; i++) {
    people[i] = new person;
    }

¿O debería hacer un objeto de personas que contenga muchos conjuntos de bytes que representen atributos de personas de esta manera?

class people() {
    this.hunger = new byte[5000]
    this.thirst = new byte[5000]

    getThirst(int i) {
        return this.thirst[i]
        }

 // and so on....

¿O estoy totalmente fuera de lugar?

ali_goes_oosh
fuente
Pregunta bastante interesante, especialmente desde 2013, más de una docena de años después de que salió RCT, la idea de tener 5000 NPC visibles e independientes en un mundo parecería completamente imposible (a pesar de los avances en tecnología)
Katana314

Respuestas:

15

La terminología común es "estructura de matrices" (SOA) y "matriz de estructuras" (AOS) que provienen de C y se ven con mayor frecuencia en términos de trabajo SIMD.

Por lo general, el enfoque AOS es más rápido, si se usa adecuadamente, pero SOA tiende a ser más fácil de trabajar (y, por lo tanto, se optimiza para la calidad más importante: el tiempo de desarrollo).

SOA, especialmente en Java, significa que sus datos pueden permanecer estrechamente empaquetados en la memoria. Puede iterar sobre las propiedades y esperar que la memoria caché de la CPU y tales permanezcan felices. Con AOS, especialmente en Java, cada objeto termina asignado "en algún lugar" en la memoria. Iterar sobre objetos podría potencialmente agotar la memoria caché de tu CPU con bastante fuerza.

Al final, tomaría el enfoque que encuentre más fácil de usar. Su tiempo de desarrollo es mucho más valioso que si su juego es compatible con PC de 10 años o solo con PC de 9 años (es muy poco probable que haga algo que necesite el último hardware).

Sean Middleditch
fuente
1
En su tercer párrafo, ¿quiere referirse a AOS dos veces? Los comentarios parecen contradictorios ...
ali_goes_oosh
Lo siento, lo arreglé.
Sean Middleditch
4

No hay ninguna razón por la que no pueda tener ambas, utilizando el patrón Facade para traducir de una interfaz a otra representación subyacente. Por ejemplo, usando los términos SOA / AOS de Sean:

Fachada SOA

class PeopleFacade {
    Person persons[5000];
    getThirst(int i) { return persons[i].thirst; }
}

Fachada AOS

class People { int thirsts[5000]; } people;
class PersonFacade {
    int i;
    getThirst() { return people.thirsts[i]; }
}

De esta manera, puede elegir libremente entre un formulario que le resulte cómodo usar , como interfaz de desarrollador, frente a lo que sea mejor como implementación por cualquier motivo, incluidos los motivos de eficiencia / caché.

Otra ventaja de la fachada es que conduce de forma muy natural al patrón Flyweight , donde utiliza una interfaz para representar a muchas más personas de las que están realmente en la memoria. Por ejemplo, quizás tenga clientes robóticos que nunca tengan sed; entonces puedes poner ese caso especial en tuPersonFacade , y los usuarios de esa interfaz nunca tienen que saber acerca de los robots:

class People { int nonRobotThirsts[1000]; } people;
class PersonFacade {
    int i;
    bool isRobot;
    getThirst() {
        if (isRobot)
            return 0;
        else
            return people.nonRobotThirsts[i];
    }
}

... o usando un enfoque más OO, tendrías una Robotclase separada que actúa exactamente como una Personexcepción getThirst().

congusbongus
fuente
-1

¡Crea objetos y guárdalos en una matriz! Hacer arreglos para el hambre y la sed puede ahorrar un poco de espacio y correr más rápido en algunas situaciones simples, pero no es POO. Java y OOP harán mucho por ti si les das una oportunidad. Para un juego realmente simple, tu segundo ejemplo podría funcionar bien, pero incluso así deberías practicar tus habilidades de OO. Su primer enfoque funcionará bien para usted, no importa cuán grande, complejo y complejo sea su programa.

Piense en todas las veces que será útil recuperar un Personobjeto de una consulta. ¿Quién envió este mensaje? por ejemplo. Muchos de los métodos que escriba querrán saber con quién están tratando. Y tendrá muchos métodos que encajarán perfectamente en una Personclase adecuada . Si Persones estático o un singleton, ¿dónde coloca los métodos que actúan sobre las personas individuales?

Si alguna vez realiza múltiples subprocesos, y con 5000 usuarios podría ser empujado a él, encontrará que la instancia principal para cada usuario es mucho más práctica.

(Y ese conjunto de personas: quédese con él por ahora, pero en algún momento querrá otros dispositivos de almacenamiento. Un mapa de algún tipo para que pueda encontrar personas por nombre. Y tal vez varias listas con diferentes claves, y probablemente grupos de enumera cada uno lo suficientemente corto como para ser matrices o listas vinculadas).

RalphChapin
fuente