<p>如果不想使用全局变量,请不要放弃<code>map</code>的结果。<code>map</code>返回每个函数返回的值,您只是忽略了它们。通过使用<code>map</code>实现其预期用途,可以使此代码更简单:</p>
<pre><code>def f(n):
return n # No need to wrap in list
with ThreadPoolExecutor(max_workers=20) as exec:
master_list = list(exec.map(f, range(1, 100)))
print(master_list)
</code></pre>
<p>如果您需要一个<code>master_list</code>来显示到目前为止计算的结果(可能有其他线程在监视它),那么只需将循环显式化:</p>
^{pr2}$
<p>这就是Executor模型的设计目的;普通线程不打算返回值,但是Executors提供了一个在幕后返回值的通道,因此您不必自己管理它。在内部,这是使用某种形式的队列,使用额外的元数据来保持结果的有序性,但是您不需要处理这种复杂性;从您的角度来看,它相当于常规的<code>map</code>函数,它只是将工作并行化。在</p>
<hr/>
<p><strong>更新</strong>以涵盖异常处理:</p>
<p>当结果命中时,<code>map</code>将引发worker中引发的任何异常。因此,如前所述,如果任何任务失败,第一组代码将不存储任何内容(将部分构造<code>list</code>,但当异常引发时将被丢弃)。第二个示例只在抛出第一个异常之前保留结果,其余的则被丢弃(您必须存储<code>map</code>迭代器并使用一些笨拙的代码来避免它)。如果您需要存储所有成功的结果,忽略失败(或只是以某种方式记录它们),最简单的方法是使用<code>submit</code>创建<code>Future</code>对象的<code>list</code>,然后按顺序或按完成顺序等待它们,将<code>.result()</code>调用包装在<code>try</code>/<code>except</code>中,以避免丢掉好的结果。例如,要按提交顺序存储结果,可以执行以下操作:</p>
^{3}$
<p>为了获得更高效的代码,您可以按照完成的顺序检索结果,而不是按提交的顺序,使用<a href="https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed" rel="nofollow noreferrer">^{<cd15>}</a>在结果完成时急切地检索结果。与以前的代码相比,唯一的变化是:</p>
<pre><code> for fut in futures:
</code></pre>
<p>变成:</p>
<pre><code> for fut in concurrent.futures.as_completed(futures):
</code></pre>
<p>在<code>as_completed</code>中,<code>as_completed</code>一旦完成/取消期货,就立即进行{<cd17>}的工作,而不是推迟到所有先前提交的期货完成并得到处理。在</p>
<p>使用<code>add_done_callback</code>还有更复杂的选项,因此主线程根本不参与显式处理结果,但这通常是不必要的,而且常常令人困惑,因此最好尽可能避免。在</p>