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

时间:2018-03-10 22:33:24

标签: python import pygame global external

因此,和我的朋友们一起在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))

这是在大约0.021秒内运行的代码(拆分为2个文件): 文件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))
编辑:正如匹配所示,我已经改变了测量时间的方法,而是使用python profiling(使用cProfile),但我获得了大致相同的结果,除了前两种方法的出现次数再长一点

2 个答案:

答案 0 :(得分:0)

使用单独的文件,首次导入文件时会发生所有getImage次调用。你没有计算导入的时间,所以你忽略了文件所做的一切的成本。

答案 1 :(得分:0)

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

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

rm *.pyc
PYTHONDONTWRITEBYTECODE=1 python mygame.py

还要记住,0.02秒的几率完全在任何系统的正常“漂移”范围内 - 这就是像timeit这样的工具运行相同代码数千次并平均结果的原因。

在这个注意事项上 - 考虑代码中可能出现的运行缓慢操作次数 - 如果您只加载一次图像,并且通过不同的方式获得的性能提升为0.02秒 - 而游戏预计会运行几分钟或者几个小时,然后这看起来像是一个过早的优化。