python脚本速度改进

2024-09-28 21:50:19 发布

您现在位置:Python中文网/ 问答频道 /正文

对于我的机器人,我正在分析激光测距数据。我每秒要分析很多样本。所以速度是必需的。 我知道python不是基于此的正确语言-但是我现在不想切换,因为我正处于原型阶段(看看我是否能摆脱它:-)。你知道吗

目前,我被困在挤出更多的速度分析代码,我有。你知道吗

我提取了相关代码并创建了一个小测试。如果有人能给我一些提示来提高这个测试脚本的速度,那就太棒了。你知道吗

from math import degrees, radians, sin, cos, fabs
import time

class NewRobotMap(object):
    def __init__(self, sizeX, sizeY, Resolution, RobotPosX, RobotPosY, RobotTheta, ServoPos, mapMaxOcc, mapMaxFree, OccValue, EmptyValue):
        self.sizeX = sizeX
        self.sizeY = sizeY
        self.RobotPosX = int(RobotPosX)
        self.RobotPosY = int(RobotPosY)
        self.mapResolution = int(Resolution)
        self.StartPosX = int(RobotPosX)
        self.StartPosY = int(RobotPosY)
        self.RobotTheta = float(RobotTheta)
        self.EmptyValue = EmptyValue
        self.ServoPos = ServoPos
        self.mapMaxOcc = mapMaxOcc
        self.mapMaxFree = mapMaxFree
        self.mapOccValue = OccValue
        self.RobotPosOldX = ""
        self.RobotPosOldY = ""

    def clear(self):
        self.RobotMap = [[self.EmptyValue for i in xrange(self.sizeY)] for j in xrange(self.sizeX)]
    def updateMap(self ,x ,y , Val):
        oldval = self.RobotMap[x][y]
        self.RobotMap[x][y]=self.RobotMap[x][y] + Val

        if self.RobotMap[x][y] > self.mapMaxOcc:
            self.RobotMap[x][y] = self.mapMaxOcc
        elif self.RobotMap[x][y] < self.mapMaxFree:
            self.RobotMap[x][y] = self.mapMaxFree
        return oldval, self.RobotMap[x][y]
    def setOcc(self,x,y):
            self.RobotMap[x][y] = self.mapMaxOcc
    def updateRobot(self,theta,x,y):
        robotThetaold=self.RobotTheta

        self.RobotTheta = float(theta)
        self.RobotPosX = int(round(self.StartPosX + float(int(x)/self.mapResolution), 0))
        self.RobotPosY = int(round(self.StartPosY - float(int(y)/self.mapResolution),0))

        if x != self.RobotPosOldX or y != self.RobotPosOldX:
            self.RobotPosOldX = x
            self.RobotPosOldY = y
            return True
        else:
            self.RobotPosOldX = x
            self.RobotPosOldY = y
            return False
    def getRobotPos(self):
        return self.RobotPosX, self.RobotPosY
    def display(self):
        s = [[str(e) for e in row] for row in self.RobotMap]
        lens = [len(max(col, key=len)) for col in zip(*s)]
        fmt = '\t'.join('{{:{}}}'.format(x) for x in lens)
        table = [fmt.format(*row) for row in s]
        print '\n'.join(table)
    def updateServoPos(self, newServoPos):
        self.ServoPos = newServoPos


templateData = {
    'MapWidth' : 800,
    'MapHeight': 600,
    'StartPosX' : 500,
    'StartPosY' : 300,
    'StartTheta' : 0,
    'Resolution' : 5,
    'mapThresholdFree' : 126,
    'mapThresholdOcc' : 130, #169
    'EmptyValue' : 128,
    'mapMaxOcc' : 137,
    'mapMaxFree' : 119,
    'ServoPos' : 0,
    'CurrentPosX' : 0,
    'CurrentPosY' : 0,
    'CurrentTheta' : 0,
    'SafeZone' : 10
}

templateData["MapHeight"] = templateData["MapHeight"] / templateData["Resolution"]
templateData["MapWidth"] = templateData["MapWidth"] / templateData["Resolution"]
templateData["StartPosX"] = templateData["StartPosX"] / templateData["Resolution"]
templateData["StartPosY"] = templateData["StartPosY"] / templateData["Resolution"]


def updateSonarCalcMapVal(val):
    mapThresholdFree = templateData["mapThresholdFree"]
    mapThresholdOcc = templateData["mapThresholdOcc"]

    #oldval
    if  val[0] <= mapThresholdFree:
        oldval = 0
    elif mapThresholdFree < val[0] < mapThresholdOcc:
        oldval = 1
    elif  val[0] >= mapThresholdOcc:
        oldval = 2

    # newval
    if  val[1] <= mapThresholdFree:
        newval = 0
    elif mapThresholdFree < val[1] < mapThresholdOcc:
        newval = 1
    elif  val[1] >= mapThresholdOcc:
        newval = 2

    if oldval != newval:
        return newval
    else:
        return 'n'


def dur( op=None, clock=[time.time()] ):
    if op != None:
        duration = time.time() - clock[0]
        print '%s finished. Duration %.6f seconds.' % (op, duration)
    clock[0] = time.time()

def updateIRWrite(RobotPos, coord, updateval):
    XtoUpdate=RobotPos[0] + coord[0]
    YtoUpdate=RobotPos[1] - coord[1]
    val = map.updateMap(XtoUpdate, YtoUpdate , updateval)
    newval=updateSonarCalcMapVal(val)

########### main Script #############

map=NewRobotMap(templateData["MapWidth"],templateData["MapHeight"], templateData["Resolution"], templateData["StartPosX"],templateData["StartPosY"], templateData["StartTheta"], templateData["ServoPos"],templateData["mapMaxOcc"],templateData["mapMaxFree"],templateData["mapThresholdOcc"],templateData["EmptyValue"])
map.clear()

dur()
for x in xrange(0,10001*40):
    updateIRWrite((100,100), (10,10), 1)
dur("loops")

我试过一个numpy数组self.RobotMap机器人地图在NewRobotMap类/对象中。但这要慢得多。你知道吗


Tags: inselffortimedefvalintresolution
2条回答

你能安装PyPy并用它而不是CPython(默认值)运行你的脚本吗?它应该作为CPython的替代品。你知道吗

它是基于(追踪?)JIT以其高运行时性能而闻名。你知道吗

一些提示

最小化太深的重定向

您的代码在这里:

def updateMap(self ,x ,y , Val):
        oldval = self.RobotMap[x][y]
        self.RobotMap[x][y]=self.RobotMap[x][y] + Val

        if self.RobotMap[x][y] > self.mapMaxOcc:
            self.RobotMap[x][y] = self.mapMaxOcc
        elif self.RobotMap[x][y] < self.mapMaxFree:
            self.RobotMap[x][y] = self.mapMaxFree
        return oldval, self.RobotMap[x][y]

是否一直重复self.RobotMap[x][y]需要4级跃点才能获得值(self->;RobotMap->;[x]->;[y])

这可以优化:

就地更新

旧的:

self.RobotMap[x][y]=self.RobotMap[x][y] + Val

新建(第二次保存现有值的跳转)

self.RobotMap[x][y] += Val

使用局部变量而不是深度嵌套结构

def updateMap(self ,x ,y , Val):
        oldval = self.RobotMap[x][y]
        newval = oldval + Val

        if newval > self.mapMaxOcc:
            newval = self.mapMaxOcc
        elif newval < self.mapMaxFree:
            newval = self.mapMaxFree
        return oldval, newval

请注意,旧的返回oldval, self.RobotMap[x][y]不仅返回一个值,而且您已经修改了self.RobotMap[x][y](因为它是可变的),因此如果您依赖它,您可能会感到惊讶。你知道吗

使用全局变量而不是tempateData字典

将dictionary更改为全局变量会稍微加快运行速度,因为它删除了一级ov间接寻址。我知道,这看起来很糟糕,但这可能会发生优化。你知道吗

跳过返回self.RobotMap[x][y]

如果没有必要,或者已经更改了该值,请考虑保存返回的self.RobotMap[x][y]。你知道吗

快速清除

更改原件:

def clear(self):
    self.RobotMap = [[self.EmptyValue for i in xrange(self.sizeY)] for j in xrange(self.sizeX)]

收件人:

def clear(self):
    self.RobotMap = self.sizeY * [self.sizeY * [self.EmptyValue]]

我的测试表明,x=3,y=5的执行速度是x=3,y=5的两倍,更大的尺寸可能更好。你知道吗

修改代码-从0.790581到0.479875秒

from math import degrees, radians, sin, cos, fabs
import time

templ_MapWidth = 800
templ_MapHeight = 600
templ_StartPosX = 500
templ_StartPosY = 300
templ_StartTheta = 0
templ_Resolution = 5
templ_mapThresholdFree = 126
templ_mapThresholdOcc = 130
templ_EmptyValue = 128
templ_mapMaxOcc = 137
templ_mapMaxFree = 119
templ_ServoPos = 0
templ_CurrentPosX = 0
templ_CurrentPosY = 0
templ_CurrentTheta = 0
templ_SafeZone = 10

templ_MapHeight  = templ_MapHeight / templ_Resolution
templ_MapWidth   = templ_MapWidth /  templ_Resolution
templ_StartPosX  = templ_StartPosX / templ_Resolution
templ_StartPosY  = templ_StartPosY / templ_Resolution

class NewRobotMap(object):
    def __init__(self, sizeX, sizeY, Resolution, RobotPosX, RobotPosY, RobotTheta, ServoPos, mapMaxOcc, mapMaxFree, OccValue, EmptyValue):
        self.sizeX = sizeX
        self.sizeY = sizeY
        self.RobotPosX = int(RobotPosX)
        self.RobotPosY = int(RobotPosY)
        self.mapResolution = int(Resolution)
        self.StartPosX = int(RobotPosX)
        self.StartPosY = int(RobotPosY)
        self.RobotTheta = float(RobotTheta)
        self.EmptyValue = EmptyValue
        self.ServoPos = ServoPos
        self.mapMaxOcc = mapMaxOcc
        self.mapMaxFree = mapMaxFree
        self.mapOccValue = OccValue
        self.RobotPosOldX = ""
        self.RobotPosOldY = ""

    def clear(self):
        self.RobotMap = self.sizeX * [self.sizeY * [self.EmptyValue]]

    def updateMap(self, x, y, Val):
        oldval = self.RobotMap[x][y]
        newval = oldval + Val

        if newval < self.mapMaxFree:
            return oldval, self.mapMaxFree
        if newval > self.mapMaxOcc:
            return oldval, self.mapMaxOcc
        return oldval, newval

    def setOcc(self, x, y):
            self.RobotMap[x][y] = self.mapMaxOcc

    def updateRobot(self, theta, x, y):
        robotThetaold = self.RobotTheta

        self.RobotTheta = float(theta)
        self.RobotPosX = int(round(self.StartPosX + float(int(x)/self.mapResolution), 0))
        self.RobotPosY = int(round(self.StartPosY - float(int(y)/self.mapResolution), 0))

        if x != self.RobotPosOldX or y != self.RobotPosOldX:
            self.RobotPosOldX = x
            self.RobotPosOldY = y
            return True
        else:
            self.RobotPosOldX = x
            self.RobotPosOldY = y
            return False

    def getRobotPos(self):
        return self.RobotPosX, self.RobotPosY

    def display(self):
        s = [[str(e) for e in row] for row in self.RobotMap]
        lens = [len(max(col, key=len)) for col in zip(*s)]
        fmt = '\t'.join('{{:{}}}'.format(x) for x in lens)
        table = [fmt.format(*row) for row in s]
        print '\n'.join(table)

    def updateServoPos(self, newServoPos):
        self.ServoPos = newServoPos

def updateSonarCalcMapVal(org, new):
    mapThresholdFree = templ_mapThresholdFree
    mapThresholdOcc = templ_mapThresholdOcc

    #oldval
    if  org <= mapThresholdFree:
        oldval = 0
    elif mapThresholdFree < org < mapThresholdOcc:
        oldval = 1
    elif  org >= mapThresholdOcc:
        oldval = 2

    # newval
    if  new <= mapThresholdFree:
        newval = 0
    elif mapThresholdFree < new < mapThresholdOcc:
        newval = 1
    elif  new >= mapThresholdOcc:
        newval = 2

    if oldval != newval:
        return newval
    else:
        return 'n'


def dur(op=None, clock=[time.time()]):
    if op != None:
        duration = time.time() - clock[0]
        print '%s finished. Duration %.6f seconds.' % (op, duration)
    clock[0] = time.time()

def updateIRWrite(RobotPos, coord, updateval):
    XtoUpdate = RobotPos[0] + coord[0]
    YtoUpdate = RobotPos[1] - coord[1]

    newval = updateSonarCalcMapVal(*mymap.updateMap(XtoUpdate, YtoUpdate, updateval))

########### main Script #############

mymap = NewRobotMap(templ_MapWidth, templ_MapHeight, templ_Resolution, templ_StartPosX, templ_StartPosY, templ_StartTheta, templ_ServoPos, templ_mapMaxOcc, templ_mapMaxFree, templ_mapThresholdOcc, templ_EmptyValue)
mymap.clear()

dur()

for x in xrange(0, 10001*40):
    updateIRWrite((100, 100), (10, 10), 1)

dur("loops")

结论

为了做正确的工作,代码肯定需要检查。例如,有些方法根本不使用,有些调用从不使用返回值。你知道吗

但可以看到一些优化。一般来说,可以遵循以下原则:

  1. 首先让代码正确运行
  2. 澄清什么是可接受的速度,如果没有必要,不要优化
  3. 测量,轮廓
  4. 在最繁忙的循环中开始优化,就有最好的机会加快速度。在它们里面,每一行代码都很重要。你知道吗

相关问题 更多 >