質問

さて、本当に最適化が必要な Python コードができました。

  • これは、小さな (80x60 ピクセル) イメージに対するライフ ゲームの反復であり、そこから RGB 値を抽出します。
  • 現在ネストされた for ループを使用しています。より高速にするには、for ループを交換したいと思います map() c 関数を使用しますが、それを行うと、x、y 値を取得する方法がわかりません。また、定義する必要がある関数の範囲外で定義されたローカル値もわかりません。
  • 使用するだろう map() この現在の for ループのセットよりも高速になるでしょうか?これを使用しても x、y を取得するにはどうすればよいでしょうか?
  • 私は現在 pygame Surfaces を使用しています。 surfarray/pixelarray モジュールですが、すべてのピクセルを変更/取得しているため、モジュールよりもはるかに遅くなります。 Surface.get_at()/set_at().
  • あと、ちょっと関係ないですが…他の言語のように、Python が数値のリストを走査するのではなく、単に数値をインクリメントするだけであれば、これをもっと速くできると思いますか?なぜ Python には foreach() だけでなく通常の for() も含まれていないのでしょうか?
  • 条件文の量もおそらく処理を遅くしますよね?最も遅い部分は、近隣ノードのチェックです (ここでリスト 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を使用しないことにより、最高速度向上を得ることができると思います。

私が最初にあなたの80×60の画像を撮影し、32ビットピクセルとプレーンなビットマップファイルに変換することをお勧めします。次いでパイソン array のオブジェクトに画素データを読み出します。今、あなたは、値を読み込む新しい値を計算し、最大速度で所定の場所に新しい値を突っつい、arrayのオブジェクトの上を歩くことができます。完了したら、あなたの新しいビットマップイメージを保存し、Surfaceに変換します。

また、24ビットのピクセルを使用することができますが、それは遅くする必要があります。 32ビットピクセルが一つのピクセルは、インデックスピクセルのアレイがはるかに容易にする1つの32ビット整数値であることを意味します。 24ビットのパックされたピクセルは、各ピクセルは、へのインデックスにはるかに迷惑である3バイトであることを意味します。

私はあなたがforの使用を避けるためにしようとするよりも、このアプローチのうち、より多くの速度を得ると確信しています。あなたはこれをしようとすると、私たちはそれが働いていたりしませんでしたどれだけ知っているようにここで何かを投稿してください。幸運ます。

編集:私はarrayは、単一のインデックスを持っていると思いました。私はあなたが動作するように2つのインデックスを得ることができたかどうかはわかりません。私はあなたがこのような何かを期待していた。

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は、単一のタイプを保持することができますので、

、あなたは私が示したように、「符号なしバイト」とタイプして、インデックスを設定することになるでしょう。

どこコース__aの実際のarray変数です。

こののどれもが参考にされていない場合は、リストにあなたのビットマップを変換してみてください、またはおそらく3つのリスト。あなたは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を使用する2番目の引数としてジェネレータ式の代わりに、リストの内包表記を使用することができます。でも、私はそれがパフォーマンスに大きな影響を与える可能性が非常に高いではないことを言うと思います。

編集:注それはgsをfor程度確かに右である...あなたのコード内の最適化を必要としている主なものであることget_atがより重要であると余計な通話を減らしませんループします。実際に、私は、あなたはので、ここで、mapとループを交換し、実際にすべてここにパフォーマンスが向上するかどうかわからないんだけど...と言ったので、私は(...恐らくは私のFPの背景)より読みやすいmapバージョンを見つけますとにかく行きます。 ; - )

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top