Python Pygame与多进程的帮助

3 投票
1 回答
1652 浏览
提问于 2025-04-16 19:50

我正在使用pygame这个库来把一张图片显示到屏幕上,同时还在运行主循环。我用多进程来处理线程,但似乎遇到了一些问题。请不要对我那些奇怪的像xml的注释太苛刻,因为我对这些还很陌生。

这是我的代码。

#Import libraries
import pygame
import os, sys
import multiprocessing as threading
import time
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1400,900), FULLSCREEN)
class loader:
    def sound(name):
        load = os.path.join("data", name)
        sound = pygame.mixer.Sound(load)
        return sound

    def song(name):
        load = os.path.join('data', name)
        song = pygame.mixer.Sound(load)
        return song

    def picture(name):
        load = os.path.join("data", name)
        image = pygame.image.load(load)
        image = image.convert()
        return image
    def movie(name):
        load = os.path.join("data", name + ".mpg")
        movie = pygame.movie.Movie(name)
        return movie











class data():
    class movies():
        #Turns out it's not supported D:
        pass
    class songs():
        theme = loader.song("theme.ogg")
    class sounds():
        fctune = loader.sound("fctune.wav")
    class pictures():
        fc = loader.picture("fc_opaque.tga")


#------------------------Logics-------------------------

def showlogo():
    screen.blit(data.pictures.fc, (0,0))
    data.sounds.fctune.play()
    time.sleep(30)



def startloops():
    logo = threading.Process(target=showlogo, args=())
    gameloop = threading.Process(target=mainloop, args=())
    logo.start()
    logo.join(None)
    gameloop.start()
    gameloop.join(None)

def mainloop():
    while 1:
        clock.tick(30)
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                sys.exit(1)
            elif event.type == MOUSEBUTTONDOWN:
                pass
            elif event.type is MOUSEBUTTONUP:
                pass
            #End of looper.


#-----------------------/Logics-------------------------



#----------------------Globals--------------------------

clock = pygame.time.Clock() 
#----------------------/Globals-------------------------


if __name__ == "__main__": startloops()

这段代码的作用是创建两个pygame窗口……(其中一个窗口应该在你调用时出现)

screen = pygame.display.set_mode((1400,900), FULLSCREEN)

所以显然它被调用了两次。嗯,看起来是多进程引起的问题。有没有人能帮帮我?

1 个回答

2

我认为发生的事情是这样的。基本上,multiprocessing模块的工作原理是把目标函数需要的所有东西复制一份,发送到一个全新的解释器中;这就是它绕过了全局解释器锁(GIL)的方法。但这也意味着一些副作用(比如全局变量的变化,或者传入但没有返回的对象的变化)不会像预期那样传播。这里有一个简单的例子:

>>> import multiprocessing
>>> d = {'a':5, 'b':6}
>>> def alter_d():
...     d['a'] = 7
...     print d
... 
>>> p = multiprocessing(target=alter_d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'module' object is not callable
>>> p = multiprocessing.Process(target=alter_d)
>>> p.start()
>>> {'a': 7, 'b': 6}

>>> d
{'a': 5, 'b': 6}

所以你可以看到,传给新进程的d版本已经被改变了。但是本地的d版本还是保持不变。

现在我对pygame的内部工作原理不太了解。但我猜,当你使用logo = threading.Process(target=showlogo, args=())创建一个新进程时,它会复制一份screen。然后,要么在复制的时候,要么在新进程中调用screen.blit(data.pictures.fc, (0,0))时,会生成一个全新的屏幕。

幸运的是,你现在使用的multiprocessing方式完全没有意义。join只是让主进程停止,等待子进程完成——根本没有并发。此外,我敢打赌pygame提供了你实际需要的任何线程功能——我怀疑你根本不需要multiprocessing。我建议你放弃它。

撰写回答