基于代理的模拟:性能问题:Python与NetLogo&餐饮 [英] agent-based simulation: performance issue: Python vs NetLogo & Repast

查看:96
本文介绍了基于代理的模拟:性能问题:Python与NetLogo&餐饮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Python 3中复制一小段Sugarscape代理仿真模型.我发现我的代码性能比NetLogo慢3倍左右.是我的代码可能有问题,还是Python的固有局限性?

I'm replicating a small piece of Sugarscape agent simulation model in Python 3. I found the performance of my code is ~3 times slower than that of NetLogo. Is it likely the problem with my code, or can it be the inherent limitation of Python?

很显然,这只是代码的一部分,但是那是Python花费三分之二的运行时间的地方.我希望如果我写的东西效率真的很低,它可能会出现在以下片段中:

Obviously, this is just a fragment of the code, but that's where Python spends two-thirds of the run-time. I hope if I wrote something really inefficient it might show up in this 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)

大致等效的 NetLogo中的代码(此片段的功能比上面的Python函数还要多) :

Roughly equivalent code in NetLogo (this fragment does a bit more than the Python function above):

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

在我的计算机上,Python代码需要15.5秒才能运行1000个步骤;在同一台笔记本电脑上,用Java在浏览器中运行的NetLogo仿真可以在不到6秒的时间内完成1000个步骤.

On my computer, the Python code takes 15.5 sec to run 1000 steps; on the same laptop, the NetLogo simulation running in Java inside the browser finishes 1000 steps in less than 6 sec.

刚刚检查了Repast,使用Java实现.而且它与5.4秒的NetLogo大致相同. Java和Python之间的最近的比较表明没有优势Java,所以我想这应该归咎于我的代码?

Just checked Repast, using Java implementation. And it's also about the same as NetLogo at 5.4 sec. Recent comparisons between Java and Python suggest no advantage to Java, so I guess it's just my code that's to blame?

我了解 MASON 应该比Repast,但最终还是运行Java.

I understand MASON is supposed to be even faster than Repast, and yet it still runs Java in the end.

推荐答案

这可能不会带来明显的提速,但是您应该意识到,与访问全局变量或属性相比,Python中的局部变量要快得多.因此,您可以尝试将内部循环中使用的某些值分配给本地变量,例如:

This probably won't give dramatic speedups, but you should be aware that local variables are quite a bit faster in Python compared to accessing globals or attributes. So you could try assigning some values that are used in the inner loop into locals, like this:

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)

Python中的函数调用也具有相对较高的开销(与Java相比),因此您可以尝试通过直接字典查找替换occupied函数来进一步优化.

Function calls in Python also have a relatively high overhead (compared to Java), so you can try to further optimize by replacing the occupied function with a direct dictionary lookup.

您还应该查看 psyco .它是用于Python的即时编译器,在某些情况下可以显着提高速度.但是,它尚不支持Python 3.x,因此您需要使用旧版本的Python.

You should also take a look at psyco. It's a just-in-time compiler for Python that can give dramatic speed improvements in some cases. However, it doesn't support Python 3.x yet, so you would need to use an older version of Python.

这篇关于基于代理的模拟:性能问题:Python与NetLogo&餐饮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆