【问题标题】:How to use Python multiprocessing to prepare images for pygame如何使用 Python 多处理为 pygame 准备图像
【发布时间】:2015-05-03 08:56:44
【问题描述】:

我正在制作一个带有非常淘气的平移和缩放效果的幻灯片应用。我正在使用 pygame。

因此,主显示屏是实时 30fps+,我不希望它在加载新图像时卡顿 - 这需要超过 1/30 秒。

所以我想使用一些并行进程来准备图像并用这些对象(它们是类的实例)提供给主进程。

我尝试过使用 threading 和多进程。线程“工作”,但它仍然跳动(我责怪python) - 当线程忙时,整个事情都会变慢!所以代码运行了,但它没有达到允许持续平滑显示的目标。

但是 multiprocess segfaults (pygame parachute) 在我从主进程接收到的准备好的图像上调用一个方法。我已经尝试过管道和队列通信——两者都会导致同样的问题。该方法一直运行直到它调用

sized = pygame.transform.scale(self.image, newsize )

然后是段错误。该类与主进程没有任何依赖关系。

pygame 不喜欢多处理吗?还有其他兼容的方式吗?有没有办法“很好”的辅助线程可能会停止线程方法的执行?

非常感谢任何帮助。很高兴发布更多代码,只是在 cmets 中询问,但除非需要,否则不想在这里倾倒大列表。

提前致谢!

编辑

这是我能做到的最简短的。 需要在底部的构造函数中提供三个jpeg文件的路径

#!/usr/bin/env python2
import pygame
import sys
import time
import re
import os
import pickle
from random import randrange, shuffle
from multiprocessing import Process, Pipe
import Queue


class Img:
    """The image objects I need to pass around"""
    def __init__(self, filename=None):
        image = pygame.image.load(filename).convert()
        self.image = pygame.transform.scale(image, (640,480))

    def getSurface(self):
        """Get a surface, blit our image onto it in right place."""
        surface = pygame.Surface((640,480))
        # xxx this next command fails
        sized = pygame.transform.scale(self.image, (640,480))
        surface.blit(sized, (0,0))
        return surface

class Floaty:
    """demo"""
    def __init__(self, fileList):
        self.fileList = fileList
        pygame.init()
        self.screen = pygame.display.set_mode((640,480))

        # open the first image to get it going
        self.img = Img(self.fileList.pop())

        # Set up parallel process for opening images
        self.parent_conn, child_conn = Pipe()
        self.feeder = Process(target=asyncPrep, args=(child_conn,))
        self.feeder.start()

    def draw(self):
        """draw the image"""
        # collect image ready-prepared by other process
        if self.parent_conn.poll():
            self.img = self.parent_conn.recv()
            print ("received ", self.img)

        # request new image
        self.parent_conn.send(self.fileList.pop())

        self.screen.blit(self.img.getSurface(), (0, 0))
        pygame.display.flip()

def asyncPrep(conn):
    """load up the files"""

    while True:
        if conn.poll(1):
            filename = conn.recv()
            print ("doing ", filename)
            img = Img(filename)
            conn.send(img)


if __name__ == '__main__':
    fileList = ['/path/to/a.jpg', 'path/to/b.jpg', 'path/to/c.jpg']
    f = Floaty(fileList)
    clock = pygame.time.Clock()
    while 1:
        f.draw()
        clock.tick(4);

当我运行这个(Python 2.7.6)时,我得到:

('doing ', '/path/to/a.jpg')
('received ', <__main__.Img instance at 0x7f2dbde2ce60>)
('doing ', '/path/to/b.jpg')
Fatal Python error: (pygame parachute) Segmentation Fault
zsh: abort (core dumped)

【问题讨论】:

  • 一个简短的可编译示例会有所帮助(如果可能的话)。无论如何:您是如何发送图像的,您可以以某种方式将其序列化然后发送吗?这可能是内存问题(线程共享内存,多进程不是)。
  • @isset 谢谢,请查看已编辑的 Q。我也尝试过酸洗,但出现“表面无法酸洗”错误。
  • 嘿,所以我遇到了一个与您非常相似的解决方案,您将图像加载到另一个进程中的字符串缓冲区,然后将该缓冲区发送到您的 openGL 上下文所在的主进程。我认为这就是您之前遇到崩溃的原因,您试图从主进程外部访问 openGL 上下文。你说这个解决方案对你有用,但是在主进程中调用 pygame.image.frombuffer() 时我仍然会有点口吃,因为这是一个将缓冲区复制到视频内存的阻塞调用。好奇你是否见过任何口吃等?我缺少什么特别的东西吗?谢谢
  • 所以我所做的是使用并行进程打开图像并将其缩小到父进程所需的最大尺寸。这样我的缓冲区相对较小,加载速度也很快。

标签: python multithreading pygame python-multiprocessing pygame-surface


【解决方案1】:

我使用多处理解决了这个问题,方法是让 Img 类将图像加载到字符串缓冲区中,存储在属性中,然后添加 postReceive 方法,将其加载到存储在图像属性中的表面中。

postReceive方法由父进程在收到子进程的Img对象后调用。

因此,孩子创建的对象没有绑定到任何 pygame-y。

    self.imageBuffer = pygame.image.tostring(
      pygame.transform.scale(image, (640,480)),
      'RGB')

那么,Img 中的新方法就是:

def: postReceive(self):
    self.image = pygame.image.frombuffer( self.imagebuffer, 'RGB' )

在此处添加对此的调用:

    # collect image ready-prepared by other process
    if self.parent_conn.poll():
        self.img = self.parent_conn.recv().postReceive()
        print ("received ", self.img)

【讨论】:

    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    • 1970-01-01
    相关资源
    最近更新 更多