好的,所以我有一段真正需要优化的Python代码。
map()
c函数替换那些for循环,但如果我这样做,我无法弄清楚如何获取x,y值,以及从范围外定义的本地值我需要定义的功能。map()
会比当前的for循环更快吗?我怎么能使用它仍然得到x,y?surfarray/pixelarray
模块,但由于我正在更改/获取每个像素,因此它比Surface.get_at()/set_at()
慢很多。代码的编辑版本:
xr = xrange(80)
yr = xrange(60)
# surface is an instance of pygame.Surface
get_at = surface.get_at()
set_at = surface.set_at()
for x in xr:
# ....
for y in yr:
# ...
pixelR = get_at((x,y))[0]
pixelG = get_at((x,y))[1]
pixelB = get_at((x,y))[2]
# ... more complex stuff here which changes R,G,B values independently of each other
set_at((x,y),(pixelR,pixelG,pixelB))
该功能的完整版本:
# xr, yr = xrange(80), xrange(60)
def live(surface,xr,yr):
randint = random.randint
set_at = surface.set_at
get_at = surface.get_at
perfect = perfectNeighbours #
minN = minNeighbours # All global variables that're defined in a config file.
maxN = maxNeighbours #
pos = actual # actual = (80,60)
n = []
append = n.append
NEIGHBOURS = 0
for y in yr: # going height-first for aesthetic reasons.
decay = randint(1,maxDecay)
growth = randint(1,maxGrowth)
for x in xr:
r, g, b, a = get_at((x,y))
del n[:]
NEIGHBOURS = 0
if x>0 and y>0 and x<pos[0]-1 and y<pos[1]-1:
append(get_at((x-1,y-1))[1])
append(get_at((x+1,y-1))[1])
append(get_at((x,y-1))[1])
append(get_at((x-1,y))[1])
append(get_at((x+1,y))[1])
append(get_at((x-1,y+1))[1])
append(get_at((x+1,y+1))[1])
append(get_at((x,y+1))[1])
for a in n:
if a > 63:
NEIGHBOURS += 1
if NEIGHBOURS == 0 and (r,g,b) == (0,0,0): pass
else:
if NEIGHBOURS < minN or NEIGHBOURS > maxN:
g = 0
b = 0
elif NEIGHBOURS==perfect:
g += growth
if g > 255:
g = 255
b += growth
if b > growth: b = growth
else:
if g > 10: r = g-10
if g > 200: b = g-100
if r > growth: g = r
g -= decay
if g < 0:
g = 0
b = 0
r -= 1
if r < 0:
r = 0
set_at((x,y),(r,g,b))
答案 0 :(得分:3)
使你的代码变慢的原因可能不是循环,它们非常快。
您的代码执行速度慢的是函数调用次数。例如
pixelR = get_at((x,y))[0]
pixelG = get_at((x,y))[1]
pixelB = get_at((x,y))[2]
很多慢于(我估计大约3次)
r, g, b, a = get_at((x,y))
每次get_at
,set_at
调用都会锁定曲面,因此使用可用方法直接访问像素会更快。最合理的是Surface.get_buffer
。
使用map
在您的示例中不起作用,因为您需要索引。只需80和60个数字,使用range()
代替xrange()
甚至可能更快。
答案 1 :(得分:2)
map(do_stuff, ((x, y) for x in xrange(80) for y in xrange(60)))
其中do_stuff
可能是这样定义的:
def do_stuff(coords):
r, g, b, a = get_at(coords)
# ... whatever you need to do with those ...
set_at(coords, (r, g, b))
您也可以使用列表推导而不是生成器表达式作为map
的第二个参数(将((x, y) ...)
替换为[(x, y) ...]
)并使用range
代替{{ 1}}。不过,我会说它不太可能对性能产生重大影响。
编辑请注意,gs肯定是关于xrange
循环不是代码中需要优化的主要内容...减少对{{1的多余调用更重要的是。事实上,我不确定用for
替换循环是否真的会改善这里的性能......话虽如此,我发现get_at
版本更具可读性(也许是因为我的FP背景...),所以你还是去吧。 ; - )
答案 2 :(得分:1)
由于您正在阅读并重写每个像素,我认为您可以通过不使用Surface
来获得最佳的速度提升。
我建议首先拍摄80x60图像并将其转换为具有32位像素的普通位图文件。然后将像素数据读入python array
对象。现在,您可以遍历array
对象,读取值,计算新值,并以最大速度将新值戳到位。完成后,保存新的位图图像,然后将其转换为Surface
。
您也可以使用24位像素,但这应该更慢。 32位像素表示一个像素是一个32位整数值,这使得像素阵列更容易索引。 24位打包像素意味着每个像素是3个字节,这对索引来说更加烦人。
我相信通过这种方法你会比试图避免使用for
获得更多的速度。如果你试试这个,请在这里发布一些东西,让我们知道它有多好用或者有用。祝你好运。
array
只有一个索引。我不确定你是如何设法让两个索引工作的。我期待你做这样的事情:
def __i(x, y):
assert(0 <= x < 80)
assert(0 <= y < 60)
i = (y*80 + x) * 4
return i
def red(x, y):
return __a[__i(x, y)]
def green(x, y):
return __a[__i(x, y) + 1]
def blue(x, y):
return __a[__i(x, y) + 2]
def rgb(x, y):
i = __i(x, y)
return __a[i], __a[i + 1], __a[i + 2]
def set_rgb(x, y, r, g, b):
i = __i(x, y)
_a[i] = r
_a[i + 1] = g
_a[i + 2] = b
# example:
r, g, b = rgb(23, 33)
由于Python array
只能包含一个类型,因此您需要将类型设置为“unsigned byte”,然后像我显示的那样进行索引。
当然__a
是实际的array
变量。
如果这些都没有用,请尝试将位图转换为列表,或者可能是三个列表。您可以使用嵌套列表来获取2D寻址。
我希望这会有所帮助。如果它没有帮助,那么我不理解你在做什么;如果你解释得更多,我会尝试改进答案。