如何使用Python多处理为pygame准备图像
我正在制作一个幻灯片应用程序,它有一个非常小的平移和缩放效果。我在用pygame 因此,主显示器是实时30fps+,我不希望它在加载新图像时出现口吃-这需要1/30秒的时间 所以我想使用一些并行进程来准备图像,并向主进程提供这些对象,这些对象是类的实例 我尝试了线程和多进程。线程'工作',但它仍然跳跃(我责备)-整个事情减慢时,线程忙!因此,代码运行了,但没有达到允许连续平滑显示的目标 但是,多进程segfaults如何使用Python多处理为pygame准备图像,python,multithreading,pygame,python-multiprocessing,pygame-surface,Python,Multithreading,Pygame,Python Multiprocessing,Pygame Surface,我正在制作一个幻灯片应用程序,它有一个非常小的平移和缩放效果。我在用pygame 因此,主显示器是实时30fps+,我不希望它在加载新图像时出现口吃-这需要1/30秒的时间 所以我想使用一些并行进程来准备图像,并向主进程提供这些对象,这些对象是类的实例 我尝试了线程和多进程。线程'工作',但它仍然跳跃(我责备)-整个事情减慢时,线程忙!因此,代码运行了,但没有达到允许连续平滑显示的目标 但是,多进程segfaults(pygame降落伞)只要我对从主进程接收到的准备好的图像调用一个方法。我尝试过
(pygame降落伞)
只要我对从主进程接收到的准备好的图像调用一个方法。我尝试过管道通信和队列通信-两者都会导致相同的问题。该方法一直运行,直到调用
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)时,我得到:
('do','/path/to/a.jpg')
(‘收到’,)
('do','/path/to/b.jpg')
致命Python错误:(pygame降落伞)分段错误
zsh:中止(堆芯转储)
我使用多处理解决了这个问题,方法是让Img类将图像加载到存储在属性中的字符串缓冲区中,然后添加一个postReceive
方法,将图像加载到存储在image属性中的曲面中
父进程从子进程接收到Img
对象后,调用postReceive
方法
因此,子对象创建的对象不绑定到任何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)
一个简短的可编译示例会有所帮助(如果可能的话)。不管怎样:你是如何发送图像的,你能把它序列化然后发送吗?这可能是内存问题(线程是共享内存的,多进程不是)。@isset谢谢,请看编辑的Q。我也尝试过酸洗,但我得到了一个“Surface Can Can Pickle”错误。嘿,所以我遇到了一个非常类似的解决方案,在另一个进程中将图像加载到字符串缓冲区,然后将该缓冲区发送到openGL上下文所在的主进程。我认为这就是为什么之前会发生崩溃的原因,您试图从主进程外部访问openGL上下文。您说这个解决方案适合您,但在主进程中调用pygame.image.frombuffer()时,我仍然会有轻微的口吃,因为这是一个将缓冲区复制到视频内存的阻塞调用。好奇你是否见过口吃等等?我遗漏了什么特别的东西?ThxSo我所做的是使用并行进程打开图像,并将其缩小到父进程所需的最大大小。这样,我的缓冲区相对较小,加载速度较快。
# collect image ready-prepared by other process
if self.parent_conn.poll():
self.img = self.parent_conn.recv().postReceive()
print ("received ", self.img)