0

Python(3.2) で Tkinter モジュールを使い始めたばかりなので、古いプログラム (curses モジュールを使用) をこのモジュールで書き直すことにしました。このプログラムは、Game of Lifeシミュレーターです。私が実装したアルゴリズムは、ユーザー インターフェイスがなくてもすぐに機能します。これは私のプログラムです(これは簡単な実験であり、キャンバスウィジェットを使用したことはありません):

#!/usr/bin/python3

import gol
import Tkinter as tk

class Application(tk.Frame):
    def __init__(self):
        self.root = tk.Tk() 
        self.root.wm_title('Canvas Experiments')
        tk.Frame.__init__(self, self.root)

        self.draw_widgets()

        self.world = gol.World(30, 30)
        self.world.cells[25][26] = True
        self.world.cells[26][26] = True
        self.world.cells[27][26] = True
        self.world.cells[25][27] = True
        self.world.cells[26][28] = True

    def draw_widgets(self):
        self.canvas = tk.Canvas(
            width = 300,
            height = 300,
            bg = '#FFF')
        self.canvas.grid(row = 0)

        self.b_next = tk.Button(
            text = 'Next',
            command = self.play)
        self.b_next.grid(row = 1)

        self.grid()

    def play(self):    
        def draw(x, y, alive): 
            if alive:   
                self.canvas.create_rectangle(x*10, y*10, x*10+9, y*10+9, fill='#F00')
            else:       
                self.canvas.create_rectangle(x*10, y*10, x*10+9, y*10+9, fill='#FFF')

        for y in range(self.world.width):
            for x in range(self.world.height):
                draw(x, y, self.world.cells[x][y])      

        self.world.evolve()

app = Application()
app.mainloop()

私はゴールを報告しませんでしたが、問題はそのモジュールにはありません。問題は、プログラムが非常に遅いことです。キャンバスをうまく使えていないと思います。

編集: ここに gol モジュールがありますが、これは問題ではないと思います...

#!/usr/bin/python3

class World:
    def __init__(self, width, height):
        self.width, self.height = width, height
        self.cells = [[False for row in range(self.height)] for column in range(self.width)]

    def neighbours(self, x, y): 
        counter = 0
        for i in range(-1, 2):
            for j in range(-1, 2):
                if ((0 <= x + i < self.width) and (0 <= y + j < self.height) and not (i == 0 and j == 0)): 
                    if self.cells[x + i][y + j]:
                        counter += 1            
        return counter        

    def evolve(self):
        cells_tmp = [[False for row in range(self.height)] for column in range(self.width)]
        for x in range(self.width):
            for y in range(self.height):
                if self.cells[x][y]:
                    if self.neighbours(x, y) == 2 or self.neighbours(x, y) == 3:
                        cells_tmp[x][y] = True  
                else:           
                    if self.neighbours(x, y) == 3:
                        cells_tmp[x][y] = True  
        self.cells = cells_tmp
4

2 に答える 2

2

以下はあなたのプロフィールの一部です:

ncalls  tottime  percall  cumtime  percall filename:lineno(function) 
125112    1.499    0.000    1.499    0.000 {method 'call' of 'tkapp' objects} 
125100    1.118    0.000    6.006    0.000 /usr/lib/python3.2/tkinter/__init__.py:2190(_create)
125109    0.942    0.000    1.749    0.000 /usr/lib/python3.2/tkinter/__init__.py:69(_cnfmerge)
125106    0.906    0.000    3.065    0.000 /usr/lib/python3.2/tkinter/__init__.py:1059(_options)
125599    0.851    0.000    0.851    0.000 main.py:10(neighbours)
500433    0.688    0.000    0.688    0.000 {built-in method isinstance}
125100    0.460    0.000    6.787    0.000 main.py:64(draw)
250210    0.341    0.000    0.341    0.000 {method 'update' of 'dict' objects}
125100    0.321    0.000    6.327    0.000 /usr/lib/python3.2/tkinter/__init__.py:2219(create_rectangle)
250205    0.319    0.000    0.319    0.000 {built-in method _flatten}
   139    0.255    0.002    8.093    0.058 main.py:63(play)
   139    0.181    0.001    1.051    0.008 main.py:19(evolve)
125109    0.134    0.000    0.134    0.000 {method 'items' of 'dict' objects}
125108    0.107    0.000    0.107    0.000 {built-in method callable}
     1    0.056    0.056    0.056    0.056 {built-in method create}

ここであなたにとって興味深いものを抽出しましょう:

cumtime   filename:lineno(function) 
0.851    main.py:10(neighbours)
6.787    main.py:64(draw)
8.093    main.py:63(play)
1.051    main.py:19(evolve)

クラス Applicationdrawのメソッドに含まれる でほとんどの時間を過ごします。play

台詞:

ncalls  tottime  percall  cumtime  percall filename:lineno(function) 
125100    1.118    0.000    6.006    0.000 /usr/lib/python3.2/tkinter/__init__.py:2190(_create)
125106    0.906    0.000    3.065    0.000 /usr/lib/python3.2/tkinter/__init__.py:1059(_options)

長方形を作成するために実際に時間を費やしていることを示します。

したがって、パフォーマンスを向上させたい場合は、インスタンス化をやめてください。それらを更新するだけです!ところで、draw二重ループの代わりに行列を使用すると、呼び出しがはるかに少なくなります。drawは遅い (累積 6.787 秒) ですが、これらのループで約 1.5 秒も無駄にすることを忘れないでください。

ちなみに、これらの二重ループを取り除くことで、evolveインgol.pyも大幅に改善できます。アルゴリズムも改善できると思います。

編集

ああ、golモジュールは「問題」の10分の1に貢献します:)

于 2013-02-05T16:09:18.617 に答える
1

私の推測では、ボードを再描画するたびに 900 個のオブジェクトの新しいグリッドを作成しているためです。何万ものオブジェクトを作成すると、キャンバスにパフォーマンスの問題が発生することが知られています。各反復で 900 個のオブジェクトを描画しているため、すぐに多くのオブジェクトが追加されます。

私のアドバイスは、30x30 の正方形のグリッドを 1 回描画するようにコードをリファクタリングすることです。その後、反復ごとに、各グリッド要素の色のみを変更する必要があります。これは、世代を非常に迅速に循環させるのに十分なはずです。

于 2013-02-05T15:17:51.697 に答える