Dlaczego pirglet jest tak powolny w porównaniu do pygame?

Oto kod. 5000 odbijających się wirujących czerwonych kwadratów. (16x16 png) W wersji pygame dostaję 30 klatek na sekundę, ale 10 fps z pirgletem. Czy OpenGl nie powinien być szybszy w tego typu sprawach?

wersja 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("...")

wersja 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("...")

cProfil wynik dla 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}

Wyjście cProfile Pyglet: - Bardzo długo, jest to wyjście częściowe, pełna wersjatutaj.

         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}
   ...

questionAnswers(2)

yourAnswerToTheQuestion