Python 为什么我的模拟人生游戏在几秒钟内就慢下来了?该怪Matplotlib吗?

Python 为什么我的模拟人生游戏在几秒钟内就慢下来了?该怪Matplotlib吗?,python,oop,matplotlib,Python,Oop,Matplotlib,我正在用python学习OOP,所以为了好玩,今天早上我制作了一个GameOfLife模拟器。当它启动时,它以每秒约20个周期的速度运行(由于添加了plt.pause(0.05)I),但在几秒钟内,它的速度降至每秒约2个周期 我无法想象这是算法本身,我也看不到任何明显的内存泄漏来源 matplotlib是否未能转储旧绘图,这是否是导致数千个重叠图像累积的问题?我尝试添加delim,但没有帮助 这其实并不重要,但我觉得我可以从答案中学到一些东西 PS如果你认为我的执行很差,那么一定要让我知道,我渴

我正在用python学习OOP,所以为了好玩,今天早上我制作了一个GameOfLife模拟器。当它启动时,它以每秒约20个周期的速度运行(由于添加了
plt.pause(0.05)
I),但在几秒钟内,它的速度降至每秒约2个周期

我无法想象这是算法本身,我也看不到任何明显的内存泄漏来源

matplotlib是否未能转储旧绘图,这是否是导致数千个重叠图像累积的问题?我尝试添加
delim
,但没有帮助

这其实并不重要,但我觉得我可以从答案中学到一些东西

PS如果你认为我的执行很差,那么一定要让我知道,我渴望学习

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import convolve
import time

class GoL():

    KERNEL = np.array([[1, 1, 1],
                       [1, 0, 1],
                       [1, 1, 1]])

    def __init__(self, width, height, p=0.3):
        self.width = width
        self.height = height
        self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])

    def play(self):
        self.plot()
        while True:
            self.cycle()

    def cycle(self):
        c = self.eval()
        for x in range(1,self.width-1):
            for y in range(1,self.height-1):
                c_val = c[x,y]
                if c_val == 3: self.matrix[x,y] = 1 #Alive regardless of whether cell alive or dead
                elif c_val < 2: self.matrix[x,y] = 0 #Dead regardless of whether cell alive or dead
                elif c_val > 3: self.matrix[x,y] = 0 #Dead regardless of whether cell alive or dead
                elif self.matrix[x,y] == 1 and c_val == 2: self.matrix[x,y] = 1 #If a living cell with 2 neighours, live
                else: self.matrix[x,y] = 0 #Only other option is dead with 2 neighbours; die
        self.plot()

    def eval(self):
        c = convolve(self.matrix, GoL.KERNEL, mode='constant')
        return c

    def plot(self):
        im = plt.imshow(self.matrix)
        plt.pause(0.05)
        del im #Added to see if speeds things up; it does not

在重用画布之前,应清除旧图形。可以使用matplotlib.pyplot.clf()清除当前图形():


希望这有帮助!:)

通过打印
plot
函数中的图像数量,您将看到以前调用的图像仍然存在

print ( len(plt.gca().images) )
在您的情况下,即使删除图像,该数字也会稳步增加,因为它仍然是轴的一部分,因此每次迭代都会重新绘制

最好只绘制一次图像,然后只更新其数据

class GoL():
    # ...

    def __init__(self, width, height, p=0.3):
        self.width = width
        self.height = height
        self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])
        self.im = plt.imshow(self.matrix)

    #  ....

    def plot(self):
        self.im.set_data(self.matrix)
        plt.pause(0.05)
        print len(plt.gca().images)
这将以恒定速度生成动画


关于在何处改进守则的问题,有两件事:

  • 使用
    matplotlib.animation.FuncAnimation
    ,因为这样更稳定,并且允许保存终止动画
  • 在numpy数组上使用条件,而不是在矩阵的所有像素上循环
  • 完整代码:

    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.ndimage import convolve
    import matplotlib.animation as animation
    
    class GoL():
    
        KERNEL = np.array([[1, 1, 1],
                           [1, 0, 1],
                           [1, 1, 1]])
    
        def __init__(self, width, height, p=0.3):
            self.width = width
            self.height = height
            self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])
            self.im = plt.imshow(self.matrix)
    
        def play(self):
            self.plot()
            self.ani= animation.FuncAnimation(plt.gcf(), self.cycle, repeat=True, interval=50 )
            plt.show()
    
        def cycle(self, n):
            c = self.eval()
            new = np.zeros_like(self.matrix)
            new[c == 3] = 1
            new[c < 2] = 0
            new[c > 3] = 0
            new[(self.matrix == 1) & (c == 2)] = 1
            self.matrix = new
            self.plot()
    
        def eval(self):
            return convolve(self.matrix, self.KERNEL, mode='constant')
    
        def plot(self):
            self.im.set_data(self.matrix)
    
    gol = GoL(width=100,height=100)
    gol.play()
    
    导入matplotlib.pyplot作为plt
    将numpy作为np导入
    从scipy.ndimage导入卷积
    将matplotlib.animation导入为动画
    类GoL():
    KERNEL=np.array([[1,1,1],
    [1, 0, 1],
    [1, 1, 1]])
    定义初始值(自身、宽度、高度,p=0.3):
    self.width=宽度
    自我高度=高度
    self.matrix=np.random.choice(a=[1,0],size=(宽度,高度),p=[p,1-p])
    self.im=plt.imshow(self.matrix)
    def播放(自我):
    self.plot()
    self.ani=animation.FuncAnimation(plt.gcf(),self.cycle,repeat=True,interval=50)
    plt.show()
    def循环(自身,n):
    c=self.eval()
    new=np.类零(自矩阵)
    新[c==3]=1
    新[c<2]=0
    新[c>3]=0
    新的[(self.matrix==1)和(c==2)]=1
    self.matrix=新
    self.plot()
    def eval(自我):
    返回卷积(self.matrix,self.KERNEL,mode='constant')
    def绘图(自):
    self.im.set_数据(self.matrix)
    gol=gol(宽度=100,高度=100)
    高尔夫球赛
    
    找到答案的最佳方法是分析代码。你是在使用matplotlibs
    ion
    还是?我添加了一个更优化、运行更快的解决方案。太棒了!非常感谢。因为您已经创建了一个新的0数组,所以可以删除行
    new[c<2]=0
    new[c>3]=0
    ,我想……谢谢您,非常直接!
    class GoL():
        # ...
    
        def __init__(self, width, height, p=0.3):
            self.width = width
            self.height = height
            self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])
            self.im = plt.imshow(self.matrix)
    
        #  ....
    
        def plot(self):
            self.im.set_data(self.matrix)
            plt.pause(0.05)
            print len(plt.gca().images)
    
    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.ndimage import convolve
    import matplotlib.animation as animation
    
    class GoL():
    
        KERNEL = np.array([[1, 1, 1],
                           [1, 0, 1],
                           [1, 1, 1]])
    
        def __init__(self, width, height, p=0.3):
            self.width = width
            self.height = height
            self.matrix = np.random.choice(a=[1, 0], size=(width, height), p=[p, 1 - p])
            self.im = plt.imshow(self.matrix)
    
        def play(self):
            self.plot()
            self.ani= animation.FuncAnimation(plt.gcf(), self.cycle, repeat=True, interval=50 )
            plt.show()
    
        def cycle(self, n):
            c = self.eval()
            new = np.zeros_like(self.matrix)
            new[c == 3] = 1
            new[c < 2] = 0
            new[c > 3] = 0
            new[(self.matrix == 1) & (c == 2)] = 1
            self.matrix = new
            self.plot()
    
        def eval(self):
            return convolve(self.matrix, self.KERNEL, mode='constant')
    
        def plot(self):
            self.im.set_data(self.matrix)
    
    gol = GoL(width=100,height=100)
    gol.play()