問題
要約された問題は、アプリケーションを PyInstaller でパッケージ化すると、MemoryErrors が左右にスローされることです。メインqueue
オブジェクトがガベージコレクションされていないことに関係があるのではないかと思いますが、ここではかなり暗闇の中にいます。ソースから実行すると 100% 正常に動作し、数 MB のメモリしか占有しません。制御不能になるのは、パッケージ化された 1 回だけです。
プログラム概要
デスクトップの画像変換(基本的にばかげた効果)を提供し、(オプションとして)画面の記録をディスクに保存するGUIアプリケーションがあります。
Python のスレッドは完全に同時実行ではないため、プログラムのすべての主要部分は個別のプロセスで実行され、共有オブジェクトmultiprocessing
を介して通信します。Queue
基本的なセットアップは次のとおりです。
これは基本的な生産者/消費者です。ScreenMonitor は画面のスナップショットを生成し、ImageProcessor が使用できるようにキューにプッシュします。プログラムのスループットの大きなポイントはqueue
オブジェクトです。プログラムに関連するほぼすべてのものがそこに転送されます - そして、メモリが上昇する速度で、そこにバックアップされなければなりません.
別のデータ ポイントとして、プログラムはソース コードから直接実行すると A-OK を実行します。複数のプロセスと大量の画像処理が行われている場合でも、数 MB の RAM しか占有しません。さらに、リークがないかどうかを確認するために、4 ~ 5 時間の長時間のストレス テストを実行しましたが、明らかではありません。ですから、PyInstaller を使うと何かおかしくなるはずです。
ソースから実行
これは、可能な限り多くの処理を可能な限り高速に実行しながら、プログラムのメモリ フットプリントです。
パッケージ版の実行
30秒ほど放置した後の状態です。約 3 ~ 4 分後にメモリ エラーが発生します。
いくつかのコード
注: 以下は大量の注釈が付けられています。私が取り出した大量のプログラム ブックがありました。したがって、以下にバグがあるように見えたり、変数の不一致がある場合は、編集が多すぎるためです。私が言っているのはプロダクションコードではありません:)
本当に、その核心は、非常に基本的な生産者/消費者パターンです。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 の実行を妨げていますか? 今のところ、私はかなり困惑しており、私のアプリは多かれ少なかれ機能していません。何か案は?