Question

Je reproduisant un petit morceau de modèle de simulation d'agent de paysage de sucre dans Python 3. J'ai trouvé que les performances de mon code sont ~ 3 fois plus lentes que celles de Netlogo. Est-ce probablement le problème avec mon code, ou peut-il être la limitation inhérente de Python?

De toute évidence, ce n'est qu'un fragment du code, mais c'est là que Python passe les deux tiers de l'exécution. J'espère que si j'ai écrit quelque chose de vraiment inefficace, cela pourrait apparaître dans ce fragment:

UP = (0, -1)
RIGHT = (1, 0)
DOWN = (0, 1)
LEFT = (-1, 0)
all_directions = [UP, DOWN, RIGHT, LEFT]
# point is just a tuple (x, y)
def look_around(self):
    max_sugar_point = self.point
    max_sugar = self.world.sugar_map[self.point].level
    min_range = 0

    random.shuffle(self.all_directions)
    for r in range(1, self.vision+1):
        for d in self.all_directions:
            p = ((self.point[0] + r * d[0]) % self.world.surface.length,
                (self.point[1] + r * d[1]) % self.world.surface.height)
            if self.world.occupied(p): # checks if p is in a lookup table (dict)
                continue
            if self.world.sugar_map[p].level > max_sugar:
                max_sugar = self.world.sugar_map[p].level
                max_sugar_point = p
    if max_sugar_point is not self.point:
        self.move(max_sugar_point)

Approximativement égal code dans netlogo (Ce fragment fait un peu plus que la fonction Python ci-dessus):

; -- The SugarScape growth and motion procedures. --
to M    ; Motion rule (page 25)
    locals [ps p v d]
    set ps (patches at-points neighborhood) with [count turtles-here = 0]
    if (count ps > 0) [
        set v psugar-of max-one-of ps [psugar]              ; v is max sugar w/in vision
        set ps ps with [psugar = v]                         ; ps is legal sites w/ v sugar
        set d distance min-one-of ps [distance myself]      ; d is min dist from me to ps agents
        set p random-one-of ps with [distance myself = d]   ; p is one of the min dist patches
        if (psugar >= v and includeMyPatch?) [set p patch-here]
        setxy pxcor-of p pycor-of p                         ; jump to p
        set sugar sugar + psugar-of p                       ; consume its sugar
        ask p [setpsugar 0]                                 ; .. setting its sugar to 0
    ]
    set sugar sugar - metabolism    ; eat sugar (metabolism)
    set age age + 1
end

Sur mon ordinateur, le code Python prend 15,5 secondes pour exécuter 1000 étapes; Sur le même ordinateur portable, la simulation Netlogo fonctionnant en Java à l'intérieur du navigateur termine 1000 étapes en moins de 6 secondes.

EDIT: Je viens de vérifier la répange, en utilisant la mise en œuvre de Java. Et c'est aussi à peu près la même que Netlogo à 5,4 secondes. Comparaisons récentes Entre Java et Python ne suggèrent aucun avantage à Java, donc je suppose que c'est juste mon code qui est à blâmer?

Edit: je comprends LE MAÇON est censé être encore plus rapide que le repast, et pourtant il exécute toujours Java à la fin.

Était-ce utile?

La solution

Cela ne donnera probablement pas de vitesses spectaculaires, mais vous devez savoir que les variables locales sont un peu plus rapides en Python par rapport à l'accès aux globaux ou aux attributs. Vous pouvez donc essayer d'attribuer certaines valeurs utilisées dans la boucle intérieure dans les habitants, comme ceci:

def look_around(self):
    max_sugar_point = self.point
    max_sugar = self.world.sugar_map[self.point].level
    min_range = 0

    selfx = self.point[0]
    selfy = self.point[1]
    wlength = self.world.surface.length
    wheight = self.world.surface.height
    occupied = self.world.occupied
    sugar_map = self.world.sugar_map
    all_directions = self.all_directions

    random.shuffle(all_directions)
    for r in range(1, self.vision+1):
        for dx,dy in all_directions:
            p = ((selfx + r * dx) % wlength,
                (selfy + r * dy) % wheight)
            if occupied(p): # checks if p is in a lookup table (dict)
                continue
            if sugar_map[p].level > max_sugar:
                max_sugar = sugar_map[p].level
                max_sugar_point = p
    if max_sugar_point is not self.point:
        self.move(max_sugar_point)

Les appels de fonction dans Python ont également une surcharge relativement élevée (par rapport à Java), vous pouvez donc essayer d'optimiser davantage en remplaçant le occupied Fonction avec une recherche directe de dictionnaire.

Vous devriez également jeter un œil à Psyco. C'est un compilateur juste à temps pour Python qui peut donner des améliorations de vitesse spectaculaires dans certains cas. Cependant, il ne prend pas encore en charge Python 3.x, vous devez donc utiliser une ancienne version de Python.

Autres conseils

Je vais deviner que la façon dont ça neighborhood est implémenté dans Netlogo est différent de la boucle double que vous avez. Plus précisément, je pense qu'ils pré-calculent un vecteur de quartier comme

n = [ [0,1],[0,-1],[1,0],[-1,0]....]

(vous auriez besoin d'un autre pour la vision = 1,2, ...) et ensuite utiliser une seule boucle n Au lieu d'une boucle imbriquée comme vous le faites. Cela élimine le besoin des multiplications.

Je ne pense pas que cela vous amènera 3X.

C'est une vieille question, mais je vous suggère de chercher à utiliser Numpy pour accélérer vos opérations. Les endroits où vous utilisez des dicts et des listes qui sont logiquement organisés (1, 2, 3, ou N-Dimensional Grid) Objet de données homogène (tous les entiers, ou tous les flotteurs, etc.) auront moins de frais généraux lorsqu'ils sont représentés et accessibles en tant que numpy tableaux.

http://numpy.org

Voici une comparaison relativement à jour de Netlogo et une version de Repast. Je ne supposerais pas nécessairement que le Repast est plus rapide. Netlogo semble contenir des algorithmes très intelligents qui peuvent compenser les coûts qu'il a.http://condor.depaul.edu/slytinen/abm/lytinen-railsback-emcsr_2012-02-17.pdf

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top