こんにちは。とりりんです。
今回は、Pythonの共有メモリのバグについて解説します。
意外と使われていないのか日本語の記事がなかったため作ってみました。
こんなことが知りたい方向けです。
- Pythonで共有メモリを使いたい方
- Linuxユーザーの方
- SharedMemoryを使いこなしたい方
共有メモリとは
共有メモリとは、プロセス間でデータのやり取りに使用できるメモリのことです。
例えば、プロセス1で作成したデータをプロセス2で使いたい時などに便利です。
Pythonでは、multiprocessingモジュールのSharedMemoryで使うことができます。
SharedMemoryはPython3.8で実装されました。
SharedMemoryにバグがある?
私がPython3.8やPython3.9で作業していたら、SharedMemoryでのバグを発見しました。
このバグはUbuntuやMacOSで発生し、Windowsでは問題ありませんでした。
恐らく、メモリ解放がうまくいってない?のだと思います。
2つのプロセスを同時に動かすことで例を示します。まずはプロセス1の処理から。
プロセス1から実行するようにしてください。
""" プロセス1での処理 """ import pickle import sys from multiprocessing import shared_memory # SharedMemory新規作成 try: shm = shared_memory.SharedMemory(create=True, size=30, name="test") except: print("メモリ作成エラー") sys.exit(1) # データ格納 while True: brother = { "1": "taro", "2": "jiro", "3": "saburo" } data = pickle.dumps(brother) shm.buf[:len(data)] = data
この処理では、まずshared_memory.SharedMemoryでtestという名前の共有メモリを作成します。
共有メモリの作成が完了したら、辞書型brotherのデータを共有メモリに格納します。
このデータ格納は無限ループにしています。
次にプロセス2の処理を示します。
""" プロセス2での処理 """ import pickle import time import sys from multiprocessing import shared_memory count = 0 start = time.time() while True: try: shm = shared_memory.SharedMemory(name="test") except: print("取得エラー") break else: try: data = pickle.loads(shm.buf) except pickle.UnpickingError: continue except: print("読み込みエラー") sys.exit(1) else: if (time.time() - start) > 5: shm.close() #shm.unlink() print("close") break
プロセス2では、プロセス1で作成したメモリ情報(brother)を読み込むプログラムです(エラー処理はかなり甘いです)。
まずプロセス1で作成した共有メモリtestを取得します。
この処理では共有メモリが作成されていなければエラーが発生します(エラー処理がまともならもう少しマシな動きをしますが…)。
共有メモリtestを取得後、メモリ内容を読み込みます。
そして、プロセス2開始から5秒後に処理を終了します。
ここでshm.close()でメモリを閉じる処理があるのですが、これが問題の内容です。
Windowsではこの処理は問題なく動きますが、Linuxでは違います。
closeしているはずなのにcloseされないのです。
UserWarningですが、UserWarning: resource_tracker: There appear to be 1 leaked shared_memory objects to clean up at shutdown
warnings.warn(‘resource_tracker: There appear to be %d ‘と出ます。
どうすりゃいいんや…という感じ。
また、shm.close()ではなくshm.unlink()に変えた場合についても見てみましょう。
プロセス2終了後にもう一度プロセス2を実行する(プロセス1は動きっぱなし)と、メモリ取得エラーが出ます。
まぁこれは正常な動きだと思うので、closeだけがおかしいみたいですね。
そして、いずれの場合もプロセス1を再起動して共有メモリを新規作成したら、プロセス2で正常にメモリ取得ができるのです。
スポンサーリンク
SharedMemoryエラーの対策
今回のエラー内容を見ると、OSごとに処理が変わっていることが原因だと思います。
そして、この改善策はないのではないかと思います。
そのため、PythonのバージョンアップによってSharedMemoryがアップデートされるのを待つべきでしょうね。
何か対処法があれば、教えていただけると嬉しいです。
まとめ
今回はPythonのSharedMemoryがLinuxで厄介だという話をしました。
結論としては、SharedMemoryのclose()がなんかおかしいので、LinuxでSharedMemoryを使うときは気をつけましょうといったところでしょうか。
対策があれば、教えていただけると非常に有難いです。
最後までご覧いただき、ありがとうございました!
↓とりりんを応援して頂けると嬉しいです!↓
にほんブログ村
コメント