Python Pyglet тормозит анимация. Медленно отрисовываются объекты на экране
Уже не однократно сталкиваюсь с проблемой торможения анимации при отрисовки различных объектов на Python. Проблема особенно обостряется, когда количество отрисовываемых объектов увеличивается. Я бы не сказал, что объектов прям слишком много: >= 200 (r=10) окружностей - уже слайд-шоу.
Я думаю, что дело не в библиотеке, которую я использую (pyglet). До этого я использовал p5py аналог p5.js тормоза были ещё сильнее (по правде говоря, создатели p5py знают что она сильно медленнее чем аналоги (Issues с GitHub'a)). Также пробовал Tkinter - думал, что чистый canvas решит мои проблемы. Но этого не произошло. И вот сейчас я запускаю код на Pyglet - получаю слайд-шоу.
Также заметил, что компьютер при тормозящей анимации начинает взлетать на реактивной тяге кулеров. При этом загрузка процессора процессом python'а никогда не превышает 20% (очень странно). Компьютер не совсем калькулятор: Intel i5-8300H 4 ядра (8 виртуальных) 2.30 GHz.
Собственно вопрос, в чем может быть проблема? Анимация 1000 точек не должна превращаться в слайд-шоу, даже если это Python.
PS. Так же я думаю, что проблема не в моем коде. Точно такой же (не про код ниже) код на p5.js дает плавную анимацию в браузере (но браузер использует видеокарту). Но на всякий случай прикладываю мой последний кол на Pyglet - это не верх оптимизации, но так медленно это работать не должно:
sketch.py
import pyglet
import random
from firework import Firework
window = pyglet.window.Window(400, 400)
main_batch = pyglet.graphics.Batch()
fireworks = [Firework(main_batch)]
@window.event
def on_draw():
window.clear()
main_batch.draw()
def update(dt):
if random.random() < 0.03:
fireworks.append(Firework(main_batch))
for f in fireworks:
f.update()
if f.done():
fireworks.remove(f)
if __name__ == '__main__':
pyglet.clock.schedule_interval(update, 1 / 120.0)
pyglet.app.run()
particle.py
import p5
import pyglet
class Particle(pyglet.shapes.Circle):
def __init__(self, x, y, color, firework, batch=None):
radius = 2
if firework:
radius = 4
super().__init__(x, y, radius, radius * 5, color, batch)
self.color = color
self.firework = firework
self.opacity = 255
self._done = False
self.acc = p5.Vector(0, 0)
if self.firework:
self.vel = p5.Vector(0, p5.random_uniform(8, 12))
else:
self.vel = p5.Vector.random_2D() * p5.random_uniform(-10, -2)
@property
def batch(self):
return self._batch
def update(self):
self.acc += p5.Vector(0, -0.2)
if not self.firework:
self.vel *= 0.9
if self.opacity > 4:
self.opacity -= 4
else:
self._done = True
self.opacity = 0
self.vel += self.acc
pos = p5.Vector(self.x, self.y) + self.vel
self.x = pos.x
self.y = pos.y
self.acc *= 0
def done(self):
return self._done
firework.py
import p5
import random
from particle import Particle
class Firework:
def __init__(self, batch):
self.color = tuple(random.randint(0, 255) for _ in range(3))
self.firework = Particle(p5.random_uniform(400), 0, self.color, True, batch=batch)
self.bach = batch
self._exploded = False
self.particles = []
def done(self):
if self._exploded and len(self.particles) == 0:
return True
else:
return False
def explode(self):
for _ in range(70):
p = Particle(self.firework.x, self.firework.y, self.color, False, batch=self.firework.batch)
self.particles.append(p)
def update(self):
if not self._exploded:
self.firework.update()
if self.firework.vel.y < 0:
self._exploded = True
self.explode()
self.firework.delete()
for p in self.particles:
p.update()
if p.done():
self.particles.remove(p)
p.delete()
Ответы (1 шт):
модуль threading
import threading
def explode(self):
ваш_код_который_хотите_сделать_многопотоковым
for i in range(5):
my_thread = threading.Thread(target=explode, args=(i,))
my_thread.start()