<p>附加到<code>d[1]</code>的新项目未打印的原因在<a href="https://docs.python.org/2/library/multiprocessing.html#multiprocessing.managers.SyncManager.list" rel="nofollow noreferrer"><em>Python</em>'s official documentation</a>中说明:</p>
<blockquote>
<p>Modifications to mutable values or items in dict and list proxies will
not be propagated through the manager, because the proxy has no way of
knowing when its values or items are modified. To modify such an item,
you can re-assign the modified object to the container proxy.</p>
</blockquote>
<p>因此,实际情况就是这样:</p>
<pre><code>from multiprocessing import Process, Manager
manager = Manager()
d = manager.dict()
def f():
# invoke d.__getitem__(), returning a local copy of the empty list assigned by the main process,
# (consider that a KeyError exception wasn't raised, so a list was definitely returned),
# and append 4 to it, however this change is not propagated through the manager,
# as it's performed on an ordinary list with which the manager has no interaction
d[1].append(4)
# convert d to string via d.__str__() (see https://docs.python.org/2/reference/datamodel.html#object.__str__),
# returning the "remote" string representation of the object (see https://docs.python.org/2/library/multiprocessing.html#multiprocessing.managers.SyncManager.list),
# to which the change above was not propagated
print d
if __name__ == '__main__':
# invoke d.__setitem__(), propagating this assignment (mapping 1 to an empty list) through the manager
d[1] = []
p = Process(target=f)
p.start()
p.join()
</code></pre>
<p>更新后,使用新列表重新分配<code>d[1]</code>,甚至再次使用相同的列表,会触发管理器传播更改:</p>
<pre><code>from multiprocessing import Process, Manager
manager = Manager()
d = manager.dict()
def f():
# perform the exact same steps, as explained in the comments to the previous code snippet above,
# but in addition, invoke d.__setitem__() with the changed item in order to propagate the change
l = d[1]
l.append(4)
d[1] = l
print d
if __name__ == '__main__':
d[1] = []
p = Process(target=f)
p.start()
p.join()
</code></pre>
<p>行<code>d[1] += [4]</code>也会起作用</p>
<hr/>
<h2>为Python 3.6或更高版本编辑:</h2>
<p><a href="https://docs.python.org/3/whatsnew/3.6.html#multiprocessing" rel="nofollow noreferrer">Since <em>Python 3.6</em></a>,per<a href="https://hg.python.org/cpython/rev/39e7307f9aee" rel="nofollow noreferrer">this changeset</a>在<a href="https://bugs.python.org/issue6766" rel="nofollow noreferrer">this issue</a>之后,还可以<a href="https://docs.python.org/3/library/multiprocessing.html#multiprocessing.managers.SyncManager.list" rel="nofollow noreferrer">use nested Proxy Objects</a>自动将对它们执行的任何更改传播到包含的代理对象。因此,将<code>d[1] = []</code>行替换为<code>d[1] = manager.list()</code>也可以纠正这个问题:</p>
<pre><code>from multiprocessing import Process, Manager
manager = Manager()
d = manager.dict()
def f():
d[1].append(4)
# the __str__() method of a dict object invokes __repr__() on each of its items,
# so explicitly invoking __str__() is required in order to print the actual list items
print({k: str(v) for k, v in d.items()}
if __name__ == '__main__':
d[1] = manager.list()
p = Process(target=f)
p.start()
p.join()
</code></pre>
<p>不幸的是,这个bug修复没有移植到<em>Python 2.7</em>(从<em>Python 2.7.13</em>开始)</p>
<hr/>
<h2>注意(在<em>Windows</em>操作系统下运行):</h2>
<p>尽管所描述的行为也适用于<em>Windows</em>操作系统,但由于依赖于不受支持的<a href="https://stackoverflow.com/q/13839935/3903832">^{<cd6>} API rather than the ^{<cd7>} system call</a>的<a href="https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods" rel="nofollow noreferrer">different process creation mechanism</a>,在<em>Windows</em>下执行附加的代码段时会失败</p>
<p>每当通过<em>多处理</em>模块创建新进程时,<em>Windows</em>就会创建一个新的<em>Python</em>解释器进程,该进程导入主模块,具有潜在的危险副作用。为了避免这个问题,以下方案编制准则是<a href="https://docs.python.org/3/library/multiprocessing.html#the-spawn-and-forkserver-start-methods" rel="nofollow noreferrer">recommended</a>:</p>
<blockquote>
<p>Make sure that the main module can be safely imported by a new <em>Python</em> interpreter without causing unintended side effects (such a starting a new process).</p>
</blockquote>
<p>因此,在<em>Windows</em>下执行附加的代码片段会由于<code>manager = Manager()</code>行而试图创建无限多的进程。通过在<code>if __name__ == '__main__'</code>子句中创建<code>Manager</code>和<code>Manager.dict</code>对象,并将<code>Manager.dict</code>对象作为参数传递给<code>f()</code>,可以很容易地解决这个问题,就像在<a href="https://stackoverflow.com/a/9536888/3903832">this answer</a>中所做的那样</p>
<p>有关这一问题的更多详情,请参阅<a href="https://stackoverflow.com/a/38236445/3903832">this answer</a></p>