3

queue.put() の速度が queue.get() の速度より速い場合、P1 プロセスが大量のメモリを使用することがわかります (P1 が大きなテキスト ファイルから絶え間なく行を挿入するため)。続いて、P2 もキューからラインを取得し終えました。P1が使っていたメモリがまだ解放されていません。この問題を解決するにはどうすればよいですか? 以下はサンプルとテストコードです。

ありがとう!

import time
from multiprocessing import Process, Queue

def addline(q):
   f = file('a big text file','r')
   line = True
   while line:
      line = f.readline()
      q.put(line, False)
   f.close()
   print "P1:finished"
   while 1:
      time.sleep(2)

def getline(q):
   f = file('/tmp/bak','w') 
   line = True
   while line:
      line=q.get()
      f.write(line)
      time.sleep(0.01)
   f.close()
   print "p2:finished"



if __name__ == "__main__":
   q = Queue()
   p1 = Process(name="addline", target=addline, args=(q,))
   p2 = Process(name="getline", target=getline, args=(q,))
   p1.start()
   p2.start()

編集: テキスト ファイル (44MB) を読み取って、/proc/pid/smaps を観察しようとしました。解放されていないメモリがヒープで Private_Dirty になっていることがわかりました。

00fb3000-04643000 rw-p 00000000 00:00 0                                  [heap]
Size:              55872 kB
Rss:               55844 kB
Pss:               55163 kB
Shared_Clean:          0 kB
Shared_Dirty:       1024 kB
Private_Clean:         0 kB
Private_Dirty:     54820 kB
Referenced:        54972 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

 

4

1 に答える 1

1

Python のガベージ コレクターは、オブジェクトが参照されなくなるとすぐにオブジェクトを削除します。書き込み速度がストレージ ハードウェアの読み取り速度に追いつくことができる限り、2 つの独立したスレッド/プロセスからファイルの内容を書き込みながら同時に読み取ることが、メモリを増やすことなく、小さなメモリ フットプリントで可能でなければなりません。ユースケースにより適したPythonの言語構造を使用すると、問題が解消されると思います。それについてコメントしてみます。

ファイルを 1 行ずつ読み取るには、次の概念を使用する必要があります。

with open('filepath') as f:
    for line in f:
        do_something_with(line)

.close()その場合、ファイルを明示的に指定する必要はありません。同じことがファイルの書き込みにも当てはまります。withここで声明について読んでください: http://effbot.org/zone/python-with-statement.htm

私の観点からは、あなたが提示したユースケースでは、「ストリームのような」アプリケーションのため、 amultiprocessing.Pipeではなく aがより適切です。multiprocessing.Queue生のファイル コンテンツをキュー内のアイテムとして表すのは奇妙に思えます。さらに、独立したサブプロセスの代わりにスレッドを使用すると、多くの通信オーバーヘッドを取り除くことができます (os.pipeスレッド間通信には を使用する必要があります)**。いずれにせよ、join()スレッドとサブプロセスは、開始後に実行する必要があります。

** ユース ケース (ファイルのコピー) では、グローバル インタープリター ロック (GIL) はパフォーマンスの問題にはなりません。

于 2012-05-21T10:47:38.290 に答える