我的机器人我正在分析激光测距数据。我需要每秒分析大量样本。所以速度是必需的。 我知道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")
我在NewRobotMap类/对象中尝试了一个numpy数组作为self.RobotMap。但这要慢得多。
答案 0 :(得分:0)
几点提示
您的代码在这里:
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个级别的跳跃来获取值(自我&gt; RobotMap - &gt; [x] - &gt; [y])
这可以优化:
旧:
self.RobotMap[x][y]=self.RobotMap[x][y] + Val
new(第二次为现有值保存潜水)
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]
(因为它是可变的),所以如果你依赖它,你可能会吃惊。
将字典更改为全局变量会加速运行,因为它删除了一个级别的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,执行速度提高了两倍,更大的尺寸可能会更好。
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 :(得分:0)
你能安装PyPy并用它来代替CPython(默认)运行你的脚本吗?它应该作为CPython的替代品。
它基于(跟踪?)JIT,因其高运行时性能而闻名。