Python使用multiprocessing的spawn启动方式时,__getattr__中调用self.a引发无限循环的原因咨询
__getattr__ enter an infinite loop when using multiprocessing with spawn start method? Let's break down exactly what's happening here, step by step:
1. Core difference between spawn and fork
- When using
fork(Unix default), the child process clones the parent's entire memory space. YourTestObjectinstance—including itsself.alambda—is copied directly, no serialization required. That’s why the code works when you removeset_start_method("spawn"). - When using
spawn, the child starts a fresh Python interpreter. The parent must serialize objects (viapickle) to pass them to the child, and the child deserializes them to reconstruct the objects.
2. Lambda functions can’t be pickled
Your TestObject’s self.a is a lambda: self.a = lambda *args: {}. Standard pickle can’t serialize lambda functions—they lack a stable name or source reference needed to reconstruct them in the child process.
When the parent tries to pickle testobject, it fails to save self.a, so this attribute is lost in the serialized data. When the child deserializes the object, the resulting TestObject instance has no a attribute at all.
3. The infinite loop trigger
When the child runs print(self.testobject), Python tries to generate a string representation of the object. The default __repr__ (used when no custom string methods are defined) will attempt to access instance attributes, or some internal mechanism will trigger a lookup for a missing attribute. Here’s the critical loop:
- The child’s
TestObjecthas noaattribute (lost during pickling). - Any attempt to access a missing attribute (like during the
printcall’s formatting) invokes__getattr__. - Your
__getattr__returnsself.a—butself.adoesn’t exist, so accessing it triggers__getattr__again. - This creates an infinite cycle:
__getattr__→ try to getself.a→__getattr__→ try to getself.a→ repeat forever.
Quick fixes to resolve this
You have a few straightforward options:
- Replace the lambda with a named function (named functions are picklable):
def a_func(*args): return {} class TestObject: def __init__(self) -> None: self.a = a_func def __getattr__(self, item): return self.a - Implement
__getstate__and__setstate__methods inTestObjectto handle serialization manually, ensuringself.ais properly reconstructed in the child. - Avoid passing objects with unpicklable attributes to spawned processes entirely.
内容的提问来源于stack exchange,提问作者Xiaobu Yang

