pyGame in a thread

2019-08-30 23:03发布

问题:

I want to use a pyGame program as a part of another process. Using the following code, pyGame doesn't seem to be processing events; it doesn't respond to the 'q' key nor does it draw the titlebar for the window. If go() is not run as a thread, it works fine. This is under OSX; I'm unsure if that's the problem or not.

import pygame, threading, random

def go():
  pygame.init()
  surf = pygame.display.set_mode((640,480))
  pygame.fastevent.init()

  while True:
    e = pygame.fastevent.poll()
    if e.type == pygame.KEYDOWN and e.unicode == 'q':
      return

    surf.set_at((random.randint(0,640), random.randint(0,480)), (255,255,255))
    pygame.display.flip()

t = threading.Thread(target=go)
t.start()
t.join()

回答1:

It's best to do the event handling and graphics in the main thread. Some environments really don't like you trying to render from other threads, and some don't like you trying to drain the event queue from them either.

It may not even be possible to do what you're hoping to do, since the process you're running within may well have its own ideas about who owns the message queue and the window you're rendering to.



回答2:

Pygame is not threadsafe and the eventloop is required to run on the main thread! Otherwise, the problem you describe can occur.

One solution is to call pygame.mainloop() from the main thread.

However,maybe you are using other modules that also require running from the main thread. There is in this case one pythonic solution. you have the possibility to run pygame mainloop with an argument. This argument means: run the mainloop for only a few seconds. Hence what you can do is create a generator that runs mainloop for a 0.1 second that you call periodically from main thread. For example:

def continue_pygame_loop():
    pygame.mainloop(0.1)
    yield

then just call continue_pygame_loop() periodically from main thread

Tkinter suffers from the same problem, but has no way to specify runloop() with a timeout. For me, this is why pygame is great!



回答3:

Not really an answer, just an affirmation of the fact that this problem does indeed occur on Mac OS X and not on Linux. I developed my program on Ubuntu and this sort of code worked fine there, but it failed as you described when I tried to run it on a Mac. Running the drawing code in the main thread instead works fine.

If this is really a limitation of either the threading module or pygame (on Mac), then I guess the only way is to restructure your program so that all drawing is handled by the main thread. Alternatively, file a bug report and see what happens.

EDIT: Another, much better, option would be to use the multiprocessing module. You could spawn a separate python process just for rendering to screen. Processes can then communicate information to each other. I'm looking into using this myself.



回答4:

Possibly a long shot, but try making sure you don't import Pygame until you're in the thread. It's just about possible that the problem is that you're importing Pygame on one thread and then using it on another. However, importing on multiple threads can have other issues. In particular, make sure that once you start the Pygame thread you wait for it to finish importing before you do anything that might cause the Python process to shut-down, or you might get a deadlock.