代码之家  ›  专栏  ›  技术社区  ›  Cheryl Lamb

Python导入全局变量比导入局部变量快?

  •  0
  • Cheryl Lamb  · 技术社区  · 7 年前

    因此,我和朋友们一起在Pygame中制作了一个游戏,我刚刚开始为主角编写动画。

    我想有几种方法可以做到这一点。或者制作一个图像列表并在列表上循环,或者制作一个包含精灵表上图片坐标的字典。

    我选择了第二个选项,现在我决定检查哪一个更快。所以我以一种非常简单的方式对它们进行编程,只是为了快速检查它们的性能。

    结果非常接近(字典为0.41,没有字典为0.40)。然后我决定,我想试试如果我选择第一个选项,除了打电话 pygame.image.load 在单独的文件中,并将动画帧存储为全局变量,然后将其导入主文件。

    我想它会很慢,因为我在某处读到python导入速度非常慢。。。但令人惊讶的是,我得到了0.021秒的结果!

    这对性能来说是一个巨大的变化,这可能对我的游戏至关重要,所以我想知道是否有人会碰巧知道为什么这种方法速度如此之快,并且仅仅是因为某些x或y,为什么在这种情况下速度更快,而在另一种情况下速度会非常慢。

    下面是与我的游戏当前状态类似的代码:

        import pygame
    import time
    start_time = time.time()
    playerSpriteSize = 192
    img = (0, 0)
    class SpriteSheet():
        def __init__(self, filename):
            self.sheet = pygame.image.load(filename).convert()
    
        def get_image(self, coords, size, flip=False):
            surf = pygame.Surface(size).convert()
            surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
            pygame.transform.flip(surf, False, True)
            surf.set_colorkey((0, 0, 0))
            surf = pygame.transform.flip(surf, flip, False)
            return surf
    
    pygame.init()
    
    displaySurface = pygame.display.set_mode((400, 400))
    x = SpriteSheet("playerAnimation.png")
    
    
    animationList = {0: (0, playerSpriteSize*0), 1: (0, playerSpriteSize*1), 2: (0, playerSpriteSize*2),
                     3: (0, playerSpriteSize*3), 4: (0, playerSpriteSize*4), 5: (0, playerSpriteSize*5),
                     6: (0, playerSpriteSize*6)}
    rounda = 0
    for i in animationList:
        a1 = x.get_image(animationList[rounda], (playerSpriteSize, playerSpriteSize))
        displaySurface.blit(a1, (30, 30))
        rounda += 1
        pygame.display.update()
    
    
    print("--- %s seconds ---" %(time.time() - start_time))
    

    现在,这是使用在主游戏循环之前加载的图像的代码:

    import pygame
    import time
    start_time = time.time()
    imageSize = 192
    img = (0, 0)
    class SpriteSheet():
        def __init__(self, filename):
            self.sheet = pygame.image.load(filename).convert()
    
        def get_image(self, coords, size, flip=False):
            surf = pygame.Surface(size).convert()
            surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
            pygame.transform.flip(surf, False, True)
            surf.set_colorkey((0, 0, 0))
            surf = pygame.transform.flip(surf, flip, False)
            return surf
    
    pygame.init()
    
    displaySurface = pygame.display.set_mode((400, 400))
    x = SpriteSheet("playerAnimation.png")
    
    a1 = x.get_image((0, 0), (imageSize, imageSize))
    a2 = x.get_image((0, 192), (imageSize, imageSize))
    a3 = x.get_image((0, 384), (imageSize, imageSize))
    a4 = x.get_image((0, 576), (imageSize, imageSize))
    a5 = x.get_image((0, 768), (imageSize, imageSize))
    a6 = x.get_image((0, 960), (imageSize, imageSize))
    a7 = x.get_image((0, 1152), (imageSize, imageSize))
    
    animationList = [a1, a2, a3, a4, a5, a6, a7]
    
    for i in animationList:
        displaySurface.blit(i, (30, 30))
        pygame.display.update()
    
    print("--- %s seconds ---" %(time.time() - start_time))
    

    这是代码(分为2个文件),运行时间约为0.021秒: 文件1(主文件)

    import pygame
    import time
    from mainDifferentExtern import a1, a2, a3, a4, a5, a6, a7
    
    
    start_time = time.time()
    imageSize = 192
    img = (0, 0)
    class SpriteSheet():
        def __init__(self, filename):
            self.sheet = pygame.image.load(filename).convert()
    
        def get_image(self, coords, size, flip=False):
            surf = pygame.Surface(size).convert()
            surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
            pygame.transform.flip(surf, False, True)
            surf.set_colorkey((0, 0, 0))
            surf = pygame.transform.flip(surf, flip, False)
            return surf
    
    pygame.init()
    
    displaySurface = pygame.display.set_mode((400, 400))
    x = SpriteSheet("playerAnimation.png")
    
    animationList = [a1, a2, a3, a4, a5, a6, a7]
    
    for i in animationList:
        displaySurface.blit(i, (30, 30))
        pygame.display.update()
    
    print("--- %s seconds ---" %(time.time() - start_time))
    

    以及从中导入的文件:

    import pygame
    imageSize = 192
    
    
    class SpriteSheet():
        def __init__(self, filename):
            self.sheet = pygame.image.load(filename).convert()
    
        def get_image(self, coords, size, flip=False):
            surf = pygame.Surface(size).convert()
            surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
            pygame.transform.flip(surf, False, True)
            surf.set_colorkey((0, 0, 0))
            surf = pygame.transform.flip(surf, flip, False)
            return surf
    
    pygame.init()
    pygame.display.set_mode((1, 1))
    x = SpriteSheet("playerAnimation.png")
    
    a1 = x.get_image((0, 0), (imageSize, imageSize))
    a2 = x.get_image((0, 192), (imageSize, imageSize))
    a3 = x.get_image((0, 384), (imageSize, imageSize))
    a4 = x.get_image((0, 576), (imageSize, imageSize))
    a5 = x.get_image((0, 768), (imageSize, imageSize))
    a6 = x.get_image((0, 960), (imageSize, imageSize))
    a7 = x.get_image((0, 1152), (imageSize, imageSize))
    

    编辑:根据match的建议,我改变了测量时间的方法,改为使用python评测(使用cProfile),但我得到的结果大致相同,只是前两种方法的时间稍微长一点

    2 回复  |  直到 7 年前
        1
  •  0
  •   match    7 年前

    我认为这里的差异是由于python为任何导入的模块编译字节码。这反过来将加快导入的加载/执行。您可以将这些视为 .pyc 原始代码旁边的目录中的文件。

    我怀疑,如果您执行以下操作,您的结果将再次平衡:

    rm *.pyc
    PYTHONDONTWRITEBYTECODE=1 python mygame.py
    

    还要记住,0.02秒的概率在任何系统的正常“漂移”范围内,这就是为什么像 timeit 多次运行同一代码并平均结果。

    在这一点上,考虑一下代码中可能出现的缓慢操作次数——如果只加载一次图像,而通过不同方式获得的性能增益为0.02秒——而游戏预计运行数分钟或数小时,那么这看起来像是过早优化。

        2
  •  0
  •   user2357112    7 年前

    使用单独的文件,所有 getImage 第一次导入文件时会发生调用。您没有对导入进行计时,因此忽略了该文件所做的一切的成本。