好了,所以我已经有了一块代码,真正需要优化。

  • 这是一个游戏的生命迭代过一个小(80x60素)图像并提取RGB值。
  • 目前正在使用嵌套为循环;我愿意交换这些循环的速度更快 map() c功能,但如果我这样做,我不知道我如何可以得到x,y值,也没有当地的价值观定义的范围的功能我需要定义。
  • 将使用 map() 以任何速度快于目前这组进循环?我怎么可能使用它,仍然得到x,y?
  • 我目前使用查看表面,我已经试过了 surfarray/pixelarray 模块,但是因为我改变/获得每一像素,这是一个很大比较慢 Surface.get_at()/set_at().
  • 此外,稍微无关紧要...你认为这可以做的更快,如果蟒蛇不是穿越一个列表中的数字,但只是递增数,就像在其他语言吗?为什么不python包括一个正常的()以及他们的foreach()?
  • 量的条件有可能使事情变得太慢,对吗?最慢的一部分检查的邻国(在那里建立的名单n)...我取代,整个位与片访问2D阵列,但它不能正常工作。

修订的版本代码:

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))
有帮助吗?

解决方案

由于你阅读和写 像素,我认为你可以得到的最佳速度的提高通过不用 Surface.

我建议第一次把你的80x60图像,并将它转换为一个普通的图文件的32位的像素。然后读取的像素数据转蟒蛇 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)

因为蟒蛇 array 可以只举行一个单一的类型,将要设置的种类,"未签字节",然后指数就像我表明。

在那里当然 __a 是的实际 array 变量。

如果没有这是有用的,试试转换您的位图进入一个清单,或者也许是三个清单。你可以使用嵌套的名单,获得2D处理的问题。

我希望这有所帮助。如果不是有帮助的,然后我不了解你在做什么;如果你解释的更多我会尝试改善的答复。

其他提示

是什么使你的代码缓慢可能是不对的循环,它们是快得令人难以置信。

什么减速做你的代码是多功能的电话。例如

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().

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 而不是的 xrange.我想说这不是很有可能有重大的影响表现,虽然。

编辑: 注意gs肯定是对的 for 循环不是主要的事情需要优化在你的代码...切割下来的多余的话 get_at 更为重要。事实上,我不确定如果替换的循环 map 实际上会改善性能在这里...说了这番话之后,我发现的 map 版本的可读性(也许是因为我FP背景...),所以在这里你去。;-)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top