pygame's API for initializing a display has a couple attractive sounding flags. Or at least, they sound attractive once you notice that updating your 320x240 window at 30fps is consuming all available cycles on your brand new Intel i9 CPU. They're
DOUBLEBUF. Hardware surfaces and double buffering is how you make graphics fast, right?
Well... no. You probably can't get a hardware surface anyway, and double buffering is unlikely to help until you figure out how to have a window larger than 320x240 anyway.
What you really need to do to get reasonable rendering performance is make sure that any images you blit to the display have the same color depth. You can do this with the
Surface.convert method (you get back a Surface when you load an image from a file, eg a png or a gif). Check the depth of your display surface and then convert your image surfaces to that depth (and just keep the converted versions). Blitting them will get hundreds of times faster.
It's a pretty simple thing, but it's easy to get distracted by
HWSURFACE and not notice the depth mismatch (like I did for three days).
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND exarkun 5621 8.9 12.1 275416 251248 ? Rl 2009 70025:19 /usr/bin/python /usr/bin/twistd -f infobot.tap
JSONEncoder.iterencodemethod, I thought it would be great used in combination with cooperate to create a producer. This would let an application serialize a large structure to JSON without multiple processes, threads, or unreasonably blocking the reactor.
from json import JSONEncoder from twisted.internet.task import cooperate class AsyncJSON(object): def __init__(self, value): self._value = value def beginProducing(self, consumer): self._consumer = consumer self._iterable = JSONEncoder().iterencode(self._value) self._consumer.registerProducer(self, True) self._task = cooperate(self._produce()) d = self._task.whenDone() d.addBoth(self._unregister) return d def pauseProducing(self): self._task.pause() def resumeProducing(self): self._task.resume() def stopProducing(self): self._task.stop() def _produce(self): for chunk in self._iterable: self._consumer.write(chunk) yield None def _unregister(self, passthrough): self._consumer.unregisterProducer() return passthrough
iterencodemethod, this avoids spending too much time generating json output at once. Instead, a little bit of the input will be serialized at a time, and each short resulting string is available from the iterator returned by
_producegenerator will iterated in a way that lets it cooperate with the reactor and other event sources/handlers. A few chunks of json data will be written to the consumer, then execution will switch away to something else, then come back and a few more will be written, and so on.
AsyncJSONin a resource:
from twisted.web.resource import Resource from twisted.web.server import NOT_DONE_YET class BigIntegerList(Resource): def render_GET(self, request): length = int(request.args['length']) d = AsyncJSON(range(length)).beginProducing(request) d.addCallback(lambda ignored: request.finish()) return NOT_DONE_YET