0

我刚开始在 Python(3.2) 中使用 Tkinter 模块,所以我决定用这个模块重写我的旧程序(我使用 curses 模块)。该程序是一个生命游戏模拟器。我实现的算法在没有用户界面的情况下运行得如此之快。这是我的程序(这是一个快速的实验,我从未使用过画布小部件):

#!/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,但问题不在该模块中。问题是程序很慢,我认为我不能很好地使用画布。

编辑:这是 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)

你大部分时间都花在了draw,包含在playApplication 类的方法中。

这些行:

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 cum. seconds),但请记住,您在这些循环中也浪费了近 1.5 秒。

顺便说一句,去掉这些双循环也可以大大提高evolvein 。gol.py我认为您也可以对算法进行一些改进。

编辑

哦,该gol模块有助于解决“问题”的十分之一:)

于 2013-02-05T16:09:18.617 回答
1

我的猜测是,这是因为每次重绘棋盘时都会创建一个包含 900 个对象的新网格。众所周知,当您创建数以万计的对象时,画布会出现性能问题。由于您在每次迭代中绘制 900 个对象,因此很快就会添加很多对象。

我的建议是重构您的代码以绘制一次 30x30 正方形的网格,然后在每次迭代中您只需要更改每个网格元素的颜色。这应该足以让您非常快速地循环几代人。

于 2013-02-05T15:17:51.697 回答