为什么pyglet比pygame慢得多?
这是代码。 5000弹跳红色正方形。 (16x16 png)在pygame版本中,我获得了30 fps,但pyglet获得了10 fps。 对于这种事情,Isnt OpenGl应该会更快吗?
pygame版本:
import pygame, sys, random
from pygame.locals import *
import cProfile
# Set FPS
FPS = 60.0
clock = pygame.time.Clock()
# Set window
WINDOWWIDTH= 800
WINDOWHEIGHT = 600
pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))
screen.fill((0,0,0))
background = screen.copy().convert()
image = pygame.image.load("square.png").convert()
class Square(object):
def __init__(self,x,y):
self.x = x
self.y = y
self.v_x = random.randint(1,100)
self.v_y = random.randint(1,100)
self.v_r = random.randint(-100,100)
self.rotation = 0
def __rep__(self):
return "Square %d,%d"%(self.x,self.y)
def update(self,dt):
if self.x > WINDOWWIDTH:
self.v_x *= -1
elif self.x < 0:
self.v_x *= -1
if self.y > WINDOWHEIGHT:
self.v_y *= -1
elif self.y < 0:
self.v_y *= -1
self.x += self.v_x * dt
self.y += self.v_y * dt
self.rotation += self.v_r * dt
def draw(self):
screen.blit(pygame.transform.rotate(image,self.rotation),(self.x,self.y))
sqrs = []
for _ in range(5000):
sqrs.append( Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1)) )
def main_loop():
tick = 0.0
elapsed = 0.0
while elapsed < 10.0:
dt = tick/1000.0
# Events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Logic
for s in sqrs:
s.update(dt)
# Drawing
screen.blit(background,(0,0))
for s in sqrs:
s.draw()
pygame.display.update()
pygame.display.set_caption('test program FPS: %s'%(clock.get_fps() ) )
tick = clock.tick(FPS)
elapsed += tick/1000.0
pygame.quit()
cProfile.run("main_loop()")
i = input("...")
pyglet版本:
import cProfile
import pyglet, random
# Disable error checking for increased performance
pyglet.options['debug_gl'] = False
from pyglet import clock
clock.set_fps_limit(60)
WINDOWWIDTH = 800
WINDOWHEIGHT = 600
FPS = 60.0
batch = pyglet.graphics.Batch()
window = pyglet.window.Window(WINDOWWIDTH,WINDOWHEIGHT)
fps_display = pyglet.clock.ClockDisplay()
image = pyglet.resource.image("square.png")
class Square(pyglet.sprite.Sprite):
def __init__(self,x,y):
pyglet.sprite.Sprite.__init__(self,img = image,batch=batch)
self.x = x
self.y = y
self.v_x = random.randint(1,100)
self.v_y = random.randint(1,100)
self.v_r = random.randint(-100,100)
def update(self,dt):
if self.x > WINDOWWIDTH:
self.v_x *= -1
elif self.x < 0:
self.v_x *= -1
if self.y > WINDOWHEIGHT:
self.v_y *= -1
elif self.y < 0:
self.v_y *= -1
self.x += self.v_x * dt
self.y += self.v_y * dt
self.rotation += self.v_r * dt
sqrs = []
for _ in range(5000):
sqrs.append( Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1)) )
elapsed = 0.0
def update(dt):
global elapsed
elapsed += dt
if elapsed >= 10.0:
clock.unschedule(update)
window.close()
else:
for s in sqrs:
s.update(dt)
@window.event
def on_draw():
window.clear()
batch.draw()
fps_display.draw()
clock.schedule_interval(update, 1.0/FPS)
if __name__ == '__main__':
cProfile.run("pyglet.app.run()")
c = input("...")
c pygame结果为pygame:
5341607 function calls in 9.429 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 9.429 9.429 <string>:1(<module>)
1335000 2.259 0.000 2.259 0.000 pygame-test.py:32(update)
1335000 1.323 0.000 5.969 0.000 pygame-test.py:46(draw)
1 0.772 0.772 9.429 9.429 pygame-test.py:55(main_loop)
1 0.000 0.000 9.429 9.429 {built-in method exec}
267 0.020 0.000 0.020 0.000 {built-in method get}
1 0.237 0.237 0.237 0.237 {built-in method quit}
1335000 3.479 0.000 3.479 0.000 {built-in method rotate}
267 0.013 0.000 0.013 0.000 {built-in method set_caption}
267 0.067 0.000 0.067 0.000 {built-in method update}
1335267 1.257 0.000 1.257 0.000 {method 'blit' of 'pygame.Surface' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
267 0.000 0.000 0.000 0.000 {method 'get_fps' of 'Clock' objects}
267 0.001 0.000 0.001 0.000 {method 'tick' of 'Clock' objects}
Pyglet cProfile输出: - 很长,这是部分输出,完整版本在这里。
9982775 function calls (9982587 primitive calls) in 10.066 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
123 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:1596(_handle_fromlist)
1 0.000 0.000 10.067 10.067 <string>:1(<module>)
11 0.000 0.000 0.000 0.000 __init__.py:1055(_ensure_string_data)
11 0.000 0.000 0.000 0.000 __init__.py:1061(_get_gl_format_and_type)
58 0.000 0.000 0.000 0.000 __init__.py:1140(clear)
75 0.000 0.000 0.012 0.000 __init__.py:1148(dispatch_event)
1 0.000 0.000 10.067 10.067 __init__.py:115(run)
...
1 0.000 0.000 0.000 0.000 lib.py:124(decorate_function)
1108 0.005 0.000 0.005 0.000 lib_wgl.py:80(__call__)
285000 1.409 0.000 9.872 0.000 pyglet-test.py:29(update)
58 0.105 0.002 9.982 0.172 pyglet-test.py:49(update)
...
855000 5.436 0.000 7.551 0.000 sprite.py:378(_update_position)
285000 0.172 0.000 2.718 0.000 sprite.py:441(_set_x)
851800 0.177 0.000 0.177 0.000 sprite.py:445(<lambda>)
285000 0.174 0.000 2.670 0.000 sprite.py:451(_set_y)
851115 0.155 0.000 0.155 0.000 sprite.py:455(<lambda>)
285000 0.182 0.000 2.692 0.000 sprite.py:461(_set_rotation)
285000 0.051 0.000 0.051 0.000 sprite.py:465(<lambda>)
...
4299 0.007 0.000 0.025 0.000 vertexattribute.py:308(get_region)
1 0.000 0.000 0.000 0.000 vertexattribute.py:380(__init__)
116 0.000 0.000 0.000 0.000 vertexattribute.py:384(enable)
116 0.000 0.000 0.000 0.000 vertexattribute.py:387(set_pointer)
1 0.000 0.000 0.000 0.000 vertexattribute.py:461(__init__)
116 0.000 0.000 0.000 0.000 vertexattribute.py:466(enable)
116 0.000 0.000 0.000 0.000 vertexattribute.py:469(set_pointer)
1 0.000 0.000 0.000 0.000 vertexattribute.py:501(__init__)
116 0.000 0.000 0.000 0.000 vertexattribute.py:508(enable)
116 0.000 0.000 0.000 0.000 vertexattribute.py:511(set_pointer)
3 0.000 0.000 0.000 0.000 vertexbuffer.py:293(__init__)
348 0.000 0.000 0.001 0.000 vertexbuffer.py:311(bind)
348 0.000 0.000 0.001 0.000 vertexbuffer.py:314(unbind)
3 0.000 0.000 0.000 0.000 vertexbuffer.py:381(__init__)
348 0.001 0.000 0.004 0.000 vertexbuffer.py:388(bind)
4299 0.006 0.000 0.016 0.000 vertexbuffer.py:420(get_region)
3 0.000 0.000 0.000 0.000 vertexbuffer.py:424(resize)
4299 0.002 0.000 0.002 0.000 vertexbuffer.py:460(__init__)
855232 0.735 0.000 1.053 0.000 vertexbuffer.py:466(invalidate)
...
855058 0.687 0.000 1.762 0.000 vertexdomain.py:581(_get_vertices)
...
4300 0.002 0.000 0.002 0.000 {built-in method POINTER}
...
841451 0.162 0.000 0.162 0.000 {built-in method cos}
...
2417/2415 0.000 0.000 0.000 0.000 {built-in method len}
855489 0.142 0.000 0.142 0.000 {built-in method max}
855469 0.176 0.000 0.176 0.000 {built-in method min}
465/407 0.000 0.000 0.000 0.000 {built-in method next}
...
841451 0.072 0.000 0.072 0.000 {built-in method radians}
62 0.000 0.000 0.000 0.000 {built-in method setattr}
841451 0.120 0.000 0.120 0.000 {built-in method sin}
...
瓶颈是Pyglet精灵旋转。 如果您评论Square update()方法中的'self.rotation'一行,您的fps几乎会翻倍。
Pyglet图像(和精灵)可以围绕任意锚点旋转。 如果你看一下pyglet/sprite.py
,你会发现这是使用Python数学模块完成的,这就是为什么它很慢。 通过使用OpenGL glRotate或甚至顶点着色器旋转精灵,似乎在这里有优化的空间。