0

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

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

所以我想使用一些并行的过程来准备图像并用这些对象提供主进程,这些对象是一个类的实例。

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

但是,一旦我对从主进程接收到的准备好的图像调用方法,进程就会出现段错误。(pygame parachute)我已经尝试过管道和队列通信——两者都会导致同样的问题。该方法一直运行直到它调用

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

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

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

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

提前致谢!

编辑

这是我能做到的尽可能短的。您需要在底部的构造函数中提供三个 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)
4

1 回答 1

0

我使用多处理解决了这个问题,方法是让 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)
于 2015-03-03T09:20:22.763 回答