总结的问题是,当我使用PyInstaller打包我的应用程序时,我正在左右抛出MemoryErrors。我怀疑它与主要queue
对象没有被垃圾收集有关,但是,我在这里很黑暗。它从源运行时运行100%正常,只占用几MB内存。只有一次打包,它就会失控。
我有GUI应用程序,它提供桌面的图像转换(基本上是愚蠢的效果),并且(作为选项)将屏幕的记录保存到磁盘。
由于Python的线程不是真正并发的,程序的所有主要部分都在一个单独的multiprocessing
进程中运行,并通过共享的Queue
对象进行通信。
基本设置如下:
它是基本的生产者/消费者。 ScreenMonitor生成屏幕的快照,这些快照被推入队列,以便ImageProcessor可以使用它们。程序的大吞吐点是queue
对象。只是与程序相关的所有都会在那里传输 - 并且按照内存爬升的速度,它必须在那里备份。
作为另一个数据点,程序在从源代码运行时运行A-OK。即使有多个进程和繁重的图像处理,它只占用几MB的RAM。另外,我进行了长达4-5小时的压力测试,以检查是否有泄漏,非显而易见。所以,PyInstaller必须要有趣。
这是程序内存占用,同时运行全开,尽可能快地处理。
这是让它运行约30秒后。大约3-4分钟后它会转入内存错误。
注意:下面有大量注释,我拿出了大量的程序簿,所以如果下面看起来有问题,或者变量不匹配,那是因为编辑过量。这是不是生产代码就是我所说的:)
真的,在它的核心,它是一个非常基本的producer/consumer pattern 。 Process2
将图片数据放入队列,Process2
对图片进行操作。
class Grabber(NoDaemonProcess):
def __init__(self, in_queue, msg_queue):
multiprocessing.Process.__init__(self)
self.queue = in_queue
self.ext_msg_queue = msg_queue
self.settings = Settings()
self.count = 0
self.name == multiprocessing.current_process().name
self.running = True
def run(self):
start_time = time.time()
current = self.grab()
img_queue = multiprocessing.Queue()
image_processor = ImageProcess(img_queue, self.save_path)
image_processor.start()
clock = Clock()
time.clock()
while self.running:
buffer_type, content, times = self.get(current, img_queue)
self.img_queue.put((buffer_type, content, times))
class ImageProcess(NoDaemonProcess):
def __init__(self, queue, save_path):
multiprocessing.Process.__init__(self)
self.in_queue = queue
self.save_path = save_path
self.running = True
# self.daemon = False
def run(self):
out_queue = Queue.Queue()
threads = []
for i in range(5):
t = ImageSaver(out_queue)
t.setDaemon(True)
t.start()
threads.append(t)
# classmethod; effects all instances
ImageSaver.setSavePath(self.save_path)
while self.running:
queue_item = self.in_queue.get()
buffer_type, content, times = queue_item
# Do stuff with image stream..
原来如此!有谁之前经历过这个吗? PyInstaller中有什么东西阻止GC运行吗?截至目前,我很难过,我的应用程序或多或少都没有功能。有任何想法吗?