3

遊んでmultiprocessingいると、次のスクリプトで、が2回呼び出されていることに気付きました__del__(子プロセスで1回、親プロセスで1回)。

class myclass(object):

    def __init__(self,val):
        self.val=val
        print ("Initializing %s"%str(self.val))

    def __del__(self):
        print ("deleting %s"%str(self.val))


if __name__ == "__main__":
    import multiprocessing
    p=multiprocessing.Pool(4)
    obj_list=p.map(myclass,range(30))
    raw_input()

このスクリプトの場合、それは問題ではありません...しかし、__del__副作用がある場合はどうなりますか?(私が考えることができる1つの可能な例は、ある種のロックファイルを解放することです)。__del__2回呼び出されないようにする方法はありますか?

4

3 に答える 3

3

__del__通常、外部リソースではなくオブジェクトをファイナライズするために使用されるため、両方のプロセスで呼び出すのが理にかなっています(もちろん、両方ともフォークの後にオブジェクトの独自のコピーを持っているため)。__del__特定のプロセスでの使用を防止することはお勧めできませんが、ファイルシステム上のファイルなど、フォークによって複製されない外部リソースを閉じるために本当に必要な場所では、デストラクタは、必要なリソースをクリーンアップする前に、本当にクリーンアップが必要かどうかを確認する必要があります。実装方法によっては、「ある種のロックファイルを解放する」場合もそうでない場合もあります。

オプションの場合はwith、ガベージコレクションの気まぐれに依存するのではなく、「」コンテキストマネージャーを使用してリソースの取得と解放を行うことを検討することをお勧めします。

于 2012-05-21T13:54:05.143 に答える
3

ロックを解放するようなことは、メソッドで行うべきことではありません。ロックを確実に解放するには、ステートメント__del__でコンテキストマネージャーとしてロックを使用することをお勧めします。with

さらに、生成されたクラスのインスタンスは異なるプロセスに存在します。サブプロセスで何かを変更しても、もちろんIPCに使用されるオブジェクト(キュー、パイプ、ロックなど)を除いて、他のサブプロセスには影響しません。マルチプロセッシングモジュール)。

もう1つは、メインプロセスに返されるインスタンスは、サブプロセスで作成されたインスタンスと同じではないということです。マルチプロセッシングの戻り値は、子プロセスでピクルスにされ、親に送信され、そこでアンピクルされます。このプロセスには*が含まれForkingPicklerます。したがって__del__、同じインスタンスで複数回呼び出されるのではなく、異なるサブプロセスの異なるインスタンスで呼び出されます。

*:ここで何が起こっているのか完全にはわかりません。誰か他の人がもっと知っているかもしれません...しかし、例の別のバージョンが役立つかもしれません:

import multiprocessing
import time
import os

class myclass(object):

    def __init__(self,val):
        self.val=val
        print ("Initializing %s - %s - %s" % (str(self.val), self, os.getpid()))

    def __del__(self):
        print ("Deleting     %s - %s - %s" % (str(self.val), self, os.getpid()))

if __name__ == "__main__":
    p = multiprocessing.Pool(3)
    obj_list=p.map(myclass,range(5))
    del p
    for o in obj_list:
        print ("Returned     %s - %s - %s" % (str(o.val), o, os.getpid()))

出力:

Initializing 0 - <__main__.myclass object at 0x7f2497fdc0d0> - 7574
Initializing 2 - <__main__.myclass object at 0x7f2497fdc110> - 7574
Deleting     0 - <__main__.myclass object at 0x7f2497fdc0d0> - 7574
Initializing 1 - <__main__.myclass object at 0x7f2497fdc150> - 7575
Initializing 3 - <__main__.myclass object at 0x7f2497fdc1d0> - 7575
Deleting     1 - <__main__.myclass object at 0x7f2497fdc150> - 7575
Initializing 4 - <__main__.myclass object at 0x7f2497fdc0d0> - 7574
Deleting     2 - <__main__.myclass object at 0x7f2497fdc110> - 7574
Returned     0 - <__main__.myclass object at 0x7f2497fdc650> - 7573
Returned     1 - <__main__.myclass object at 0x7f2497fdc7d0> - 7573
Returned     2 - <__main__.myclass object at 0x7f2497fdc810> - 7573
Returned     3 - <__main__.myclass object at 0x7f2497fdc850> - 7573
Returned     4 - <__main__.myclass object at 0x7f2497fdc890> - 7573
Deleting     3 - <__main__.myclass object at 0x7f2497fdc1d0> - 7575
Deleting     4 - <__main__.myclass object at 0x7f2497fdc890> - 7573
Deleting     3 - <__main__.myclass object at 0x7f2497fdc850> - 7573
Deleting     2 - <__main__.myclass object at 0x7f2497fdc810> - 7573
Deleting     1 - <__main__.myclass object at 0x7f2497fdc7d0> - 7573
Deleting     0 - <__main__.myclass object at 0x7f2497fdc650> - 7573

異なるプロセスとオブジェクトIDに注意してください

于 2012-05-21T14:08:31.467 に答える
1

特にマルチプロセッシングを伴う場合、__ del__がゼロ、1回、または複数回呼び出されるという保証はまったくありません。ロックを解除するなどの目的でこれに依存するべきではありません。__del__はかなり後で呼び出されるか、まったく呼び出されない可能性があり、リリースは行われません。アドバイスに従って、コンテキストマネージャーを使用する必要があります。

また、CPythonは参照サイクルで__del__メソッドを使用してオブジェクトのコレクションのみを延期しますが(refcount gcの代わりにCyclicを使用)、他のPython実装が同じように動作するという保証はありません。

于 2012-05-21T15:54:26.573 に答える