uTools-Manuals/docs/python/threading.html
2019-04-21 11:50:48 +08:00

58 lines
97 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="body" role="main"><div class="section" id="module-threading"><h1><span class="yiyi-st" id="yiyi-10">17.1. <a class="reference internal" href="#module-threading" title="threading: Thread-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">threading</span></code></a> — 基于线程的并行性</span></h1><p><span class="yiyi-st" id="yiyi-11"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/threading.py">Lib/threading.py</a></span></p><p><span class="yiyi-st" id="yiyi-12">此模块在较低级别的<a class="reference internal" href="_thread.html#module-_thread" title="_thread: Low-level threading API."><code class="xref py py-mod docutils literal"><span class="pre">_thread</span></code></a>模块之上构建更高级别的线程接口。</span><span class="yiyi-st" id="yiyi-13">另请参见<a class="reference internal" href="queue.html#module-queue" title="queue: A synchronized queue class."><code class="xref py py-mod docutils literal"><span class="pre">queue</span></code></a>模块。</span></p><p><span class="yiyi-st" id="yiyi-14"><a class="reference internal" href="dummy_threading.html#module-dummy_threading" title="dummy_threading: Drop-in replacement for the threading module."><code class="xref py py-mod docutils literal"><span class="pre">dummy_threading</span></code></a>模块用于<a class="reference internal" href="#module-threading" title="threading: Thread-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">threading</span></code></a>无法使用,因为<a class="reference internal" href="_thread.html#module-_thread" title="_thread: Low-level threading API."><code class="xref py py-mod docutils literal"><span class="pre">_thread</span></code></a>缺失的情况。</span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-15"></span></p><p class="last"><span class="yiyi-st" id="yiyi-16">虽然下面没有列出但是这个模块仍然支持Python 2.x系列中此模块中某些方法和函数使用的<code class="docutils literal"><span class="pre">camelCase</span></code>名称。</span></p></div><p><span class="yiyi-st" id="yiyi-17">本模块定义了以下函数︰</span></p><dl class="function"><dt id="threading.active_count"><span class="yiyi-st" id="yiyi-18"> <code class="descclassname">threading.</code><code class="descname">active_count</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-19">返回当前处于alive状态的<a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a>对象的个数。</span><span class="yiyi-st" id="yiyi-20">返回的数目等于<a class="reference internal" href="#threading.enumerate" title="threading.enumerate"><code class="xref py py-func docutils literal"><span class="pre">enumerate()</span></code></a>返回的列表的长度。</span></p></dd></dl><dl class="function"><dt id="threading.current_thread"><span class="yiyi-st" id="yiyi-21"> <code class="descclassname">threading.</code><code class="descname">current_thread</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-22">返回当前的<a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a>对象,对应于调用者控制的线程。</span><span class="yiyi-st" id="yiyi-23">如果调用者控制的线程不是通过<a class="reference internal" href="#module-threading" title="threading: Thread-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">threading</span></code></a>模块创建的,则返回一个只有有限功能的虚假线程对象。</span></p></dd></dl><dl class="function"><dt id="threading.get_ident"><span class="yiyi-st" id="yiyi-24"> <code class="descclassname">threading.</code><code class="descname">get_ident</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-25">返回当前线程的'线程标识符'。</span><span class="yiyi-st" id="yiyi-26">它是一个非零的整数。</span><span class="yiyi-st" id="yiyi-27">它的价值没有直接的意义它旨在作为要使用的魔术cookie。</span><span class="yiyi-st" id="yiyi-28">索引线程特定数据的字典。</span><span class="yiyi-st" id="yiyi-29">当一个线程退出另外一个线程创建时线程的ID可以重用。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-30"><span class="versionmodified">版本3.3中的新功能。</span></span></p></div></dd></dl><dl class="function"><dt id="threading.enumerate"><span class="yiyi-st" id="yiyi-31"> <code class="descclassname">threading.</code><code class="descname">enumerate</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-32">返回当前活着的<a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a>对象的列表。</span><span class="yiyi-st" id="yiyi-33">该列表包括守护线程、由<a class="reference internal" href="#threading.current_thread" title="threading.current_thread"><code class="xref py py-func docutils literal"><span class="pre">current_thread()</span></code></a>创建的虚假线程对象和主线程。</span><span class="yiyi-st" id="yiyi-34">它不包括已终止的线程和尚未开始的线程。</span></p></dd></dl><dl class="function"><dt id="threading.main_thread"><span class="yiyi-st" id="yiyi-35"> <code class="descclassname">threading.</code><code class="descname">main_thread</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-36">返回主 <a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a> 对象。</span><span class="yiyi-st" id="yiyi-37">在正常情况下,主线程是从 Python 解释器中启动的线程。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-38"><span class="versionmodified">版本3.4中的新功能。</span></span></p></div></dd></dl><dl class="function"><dt id="threading.settrace"><span class="yiyi-st" id="yiyi-39"> <code class="descclassname">threading.</code><code class="descname">settrace</code><span class="sig-paren">(</span><em>func</em><span class="sig-paren">)</span></span></dt><dd><p id="index-0"><span class="yiyi-st" id="yiyi-40">为所有从<a class="reference internal" href="#module-threading" title="threading: Thread-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">threading</span></code></a>模块启动的线程设置一个跟踪函数。</span><span class="yiyi-st" id="yiyi-41">在每个线程的<a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法调用之前,<em>func</em>将传递给<a class="reference internal" href="sys.html#sys.settrace" title="sys.settrace"><code class="xref py py-func docutils literal"><span class="pre">sys.settrace()</span></code></a></span></p></dd></dl><dl class="function"><dt id="threading.setprofile"><span class="yiyi-st" id="yiyi-42"> <code class="descclassname">threading.</code><code class="descname">setprofile</code><span class="sig-paren">(</span><em>func</em><span class="sig-paren">)</span></span></dt><dd><p id="index-1"><span class="yiyi-st" id="yiyi-43">为所有从<a class="reference internal" href="#module-threading" title="threading: Thread-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">threading</span></code></a>模块启动的线程设置一个profile函数。</span><span class="yiyi-st" id="yiyi-44">这个<em>profile</em>函数将在每个线程的<a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法被调用之前传递给<a class="reference internal" href="sys.html#sys.setprofile" title="sys.setprofile"><code class="xref py py-func docutils literal"><span class="pre">sys.setprofile()</span></code></a></span></p></dd></dl><dl class="function"><dt id="threading.stack_size"><span class="yiyi-st" id="yiyi-45"> <code class="descclassname">threading.</code><code class="descname">stack_size</code><span class="sig-paren">(</span><span class="optional">[</span><em>size</em><span class="optional">]</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-46">返回创建新的线程时该线程使用的栈的大小。</span><span class="yiyi-st" id="yiyi-47">可选的<em>size</em>参数指定用于随后创建的线程的堆栈大小并且必须为0使用平台或已配置的默认值或至少为32,76832 KiB的正整数值。</span><span class="yiyi-st" id="yiyi-48">如果未指定<em>size</em>则使用0。</span><span class="yiyi-st" id="yiyi-49">如果不支持更改线程堆栈大小,则会引发<a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span><span class="yiyi-st" id="yiyi-50">如果指定的栈的大小不合法,则引发一个<a class="reference internal" href="exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal"><span class="pre">ValueError</span></code></a>且栈的大小不会改变。</span><span class="yiyi-st" id="yiyi-51">32 KiB是当前支持的最小堆栈大小值以保证解释器本身有足够的堆栈空间。</span><span class="yiyi-st" id="yiyi-52">请注意,一些平台可能对堆栈大小的值有特殊限制,例如要求最小堆栈大小&gt; 32 KiB或需要分配系统内存页大小的倍数 - 有关更多信息请参阅平台文档4 KiB页是常见的使用4096的倍数作为堆栈大小是在没有更具体信息的情况下的建议方法</span><span class="yiyi-st" id="yiyi-53">可用的平台Windows、 带有POSIX线程的系统。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-54">该模块还定义了以下常量:</span></p><dl class="data"><dt id="threading.TIMEOUT_MAX"><span class="yiyi-st" id="yiyi-55"> <code class="descclassname">threading.</code><code class="descname">TIMEOUT_MAX</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-56">这个 <em>timeout</em>参数表示阻塞函数 (<a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">Lock.acquire()</span></code></a>, <a class="reference internal" href="#threading.RLock.acquire" title="threading.RLock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">RLock.acquire()</span></code></a>, <a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">Condition.wait()</span></code></a>, 等)所允许等待的最长时限。</span><span class="yiyi-st" id="yiyi-57">指定超过此值的超时将引发<a class="reference internal" href="exceptions.html#OverflowError" title="OverflowError"><code class="xref py py-exc docutils literal"><span class="pre">OverflowError</span></code></a></span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-58"><span class="versionmodified">版本3.2中的新功能。</span></span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-59">下面的章节中详细说明了这个模块所定义的一系列类。</span></p><p><span class="yiyi-st" id="yiyi-60">本模块的设计零散地基于Java的线程模型。</span><span class="yiyi-st" id="yiyi-61">然而Java的锁和条件变量是每个对象的基本行为在Python中它们是单独的对象。</span><span class="yiyi-st" id="yiyi-62">Python的<a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a>类支持Java Thread类的行为的一个子集当前没有优先级没有线程组线程不能被销毁停止挂起恢复或中断。</span><span class="yiyi-st" id="yiyi-63">Java线程类的静态方法如果实现则映射成模块级别的函数。</span></p><p><span class="yiyi-st" id="yiyi-64">下述所有方法的执行都是原子的。</span></p><div class="section" id="thread-local-data"><h2><span class="yiyi-st" id="yiyi-65">17.1.1. </span><span class="yiyi-st" id="yiyi-66">线程本地数据</span></h2><p><span class="yiyi-st" id="yiyi-67">线程本地数据是指值特定于具体线程的数据。</span><span class="yiyi-st" id="yiyi-68">要管理线程本地数据,只需创建 <a class="reference internal" href="#threading.local" title="threading.local"><code class="xref py py-class docutils literal"><span class="pre">local</span></code></a>(或其子类)的一个实例并在它上面存储属性:</span></p><pre><code class="language-python"><span></span><span class="n">mydata</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">local</span><span class="p">()</span>
<span class="n">mydata</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mi">1</span>
</code></pre><p><span class="yiyi-st" id="yiyi-69">该实例的值对于各自的线程将是不同的。</span></p><dl class="class"><dt id="threading.local"><span class="yiyi-st" id="yiyi-70"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">local</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-71">表示线程本地数据的一个类。</span></p><p><span class="yiyi-st" id="yiyi-72">更多的细节和扩展示例,参见<code class="xref py py-mod docutils literal"><span class="pre">_threading_local</span></code>模块的文档字符串。</span></p></dd></dl></div><div class="section" id="thread-objects"><h2><span class="yiyi-st" id="yiyi-73">17.1.2. </span><span class="yiyi-st" id="yiyi-74">Thread 对象</span></h2><p><span class="yiyi-st" id="yiyi-75"><a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a>类表示在单独的控制线程中运行的活动。</span><span class="yiyi-st" id="yiyi-76">有两种方式来指定活动︰ 通过将一个可调用对象传递到构造函数中,或通过重写子类中的 <a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a> 方法。</span><span class="yiyi-st" id="yiyi-77">没有其他方法(除了构造函数)应在子类中重写。</span><span class="yiyi-st" id="yiyi-78">换句话说,<em>只可以</em>重写这个类的 <code class="xref py py-meth docutils literal"><span class="pre">__init__()</span></code><a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a> 方法。</span></p><p><span class="yiyi-st" id="yiyi-79">一旦创建了一个线程对象,必须通过调用线程的 <a class="reference internal" href="#threading.Thread.start" title="threading.Thread.start"><code class="xref py py-meth docutils literal"><span class="pre">start()</span></code></a> 方法启动它的活动。</span><span class="yiyi-st" id="yiyi-80">这将在单独可控线程中调用 <a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a> 方法。</span></p><p><span class="yiyi-st" id="yiyi-81">一旦线程活动启动,该线程被视为 '活着'。</span><span class="yiyi-st" id="yiyi-82">当其 <a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a> 方法终止 —— 正常终止或者引发一个未处理的异常时,它将不再是活着。</span><span class="yiyi-st" id="yiyi-83"><a class="reference internal" href="#threading.Thread.is_alive" title="threading.Thread.is_alive"><code class="xref py py-meth docutils literal"><span class="pre">is_alive()</span></code></a> 方法测试线程是否还活着。</span></p><p><span class="yiyi-st" id="yiyi-84">其他线程可以调用线程的 <a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a> 方法。</span><span class="yiyi-st" id="yiyi-85">这会阻塞调用线程,直到 <a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a> 方法被调用的线程终止。</span></p><p><span class="yiyi-st" id="yiyi-86">一个线程有一个名称。</span><span class="yiyi-st" id="yiyi-87">这个名称可以传递给构造函数,并通过 <a class="reference internal" href="#threading.Thread.name" title="threading.Thread.name"><code class="xref py py-attr docutils literal"><span class="pre">name</span></code></a> 属性读取或更改。</span></p><p><span class="yiyi-st" id="yiyi-88">一个线程可以被标记为"daemon thread"。</span><span class="yiyi-st" id="yiyi-89">该标志的意思是整个 Python 程序在只剩下守护线程时才退出。</span><span class="yiyi-st" id="yiyi-90">它的初始值继承自创建它的线程。</span><span class="yiyi-st" id="yiyi-91">可以通过 <a class="reference internal" href="#threading.Thread.daemon" title="threading.Thread.daemon"><code class="xref py py-attr docutils literal"><span class="pre">daemon</span></code></a> 属性或 <em>daemon</em> 构造函数参数设置该标志。</span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-92"></span></p><p class="last"><span class="yiyi-st" id="yiyi-93">守护线程在关机时被意外地终止。</span><span class="yiyi-st" id="yiyi-94">他们的资源(如打开文件,数据库事务等)</span><span class="yiyi-st" id="yiyi-95">可能无法正常释放。</span><span class="yiyi-st" id="yiyi-96">如果你想你的线程优雅地停止,可以把他们设置为为非守护的并使用一个合适的信号机制例如一个<a class="reference internal" href="#threading.Event" title="threading.Event"><code class="xref py py-class docutils literal"><span class="pre">Event</span></code></a></span></p></div><p><span class="yiyi-st" id="yiyi-97">有一个“主线程”对象这对应于Python程序中的初始控制线程。</span><span class="yiyi-st" id="yiyi-98">它不是一个守护线程。</span></p><p><span class="yiyi-st" id="yiyi-99">有种可能是创建的是“虚拟的线程对象”。</span><span class="yiyi-st" id="yiyi-100">这些线程对象对应于“异质的线程”它们是在threading模块之外启动的控制线程例如直接从C代码中启动的线程。</span><span class="yiyi-st" id="yiyi-101">虚拟线程对象的功能有限;它们总是被认为是活的和守护进程的,并且不能<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a></span><span class="yiyi-st" id="yiyi-102">它们永远不会被删除,因为异质线程的终止不可能检测到。</span></p><dl class="class"><dt id="threading.Thread"><span class="yiyi-st" id="yiyi-103"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Thread</code><span class="sig-paren">(</span><em>group=None</em>, <em>target=None</em>, <em>name=None</em>, <em>args=()</em>, <em>kwargs={}</em>, <em>*</em>, <em>daemon=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-104">应该始终以关键字参数调用该构造函数。</span><span class="yiyi-st" id="yiyi-105">参数有:</span></p><p><span class="yiyi-st" id="yiyi-106"><em>group</em>应为<code class="docutils literal"><span class="pre">None</span></code>;保留用于在实现<code class="xref py py-class docutils literal"><span class="pre">ThreadGroup</span></code>类时的未来扩展。</span></p><p><span class="yiyi-st" id="yiyi-107"><em>target</em>是将被<a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法调用的可调用对象。</span><span class="yiyi-st" id="yiyi-108">默认为<code class="docutils literal"><span class="pre">None</span></code>,表示不调用任何东西。</span></p><p><span class="yiyi-st" id="yiyi-109"><em>name</em>是线程的名字。</span><span class="yiyi-st" id="yiyi-110">默认情况下以“Thread-<em>N</em>”的形式构造一个唯一的名字,<em>N</em>是一个小的十进制整数。</span></p><p><span class="yiyi-st" id="yiyi-111"><em>args</em>是给调用目标的参数元组。</span><span class="yiyi-st" id="yiyi-112">默认为<code class="docutils literal"><span class="pre">()</span></code></span></p><p><span class="yiyi-st" id="yiyi-113"><em>kwargs</em>是给调用目标的关键字参数的一个字典。</span><span class="yiyi-st" id="yiyi-114">默认为<code class="docutils literal"><span class="pre">{}</span></code></span></p><p><span class="yiyi-st" id="yiyi-115">如果不是<code class="docutils literal"><span class="pre">None</span></code><em>守护程序</em>显式设置线程是否为daemonic。</span><span class="yiyi-st" id="yiyi-116">如果<code class="docutils literal"><span class="pre">None</span></code>默认值daemonic属性从当前线程继承。</span></p><p><span class="yiyi-st" id="yiyi-117">如果子类覆盖该构造函数,它必须保证在对线程做任何事之前调用基类的构造函数(<code class="docutils literal"><span class="pre">Thread.__init__()</span></code>)。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-118"><span class="versionmodified">在版本3.3中已更改:</span>添加了<em>守护程序</em>参数。</span></p></div><dl class="method"><dt id="threading.Thread.start"><span class="yiyi-st" id="yiyi-119"> <code class="descname">start</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-120">开始线程的活动。</span></p><p><span class="yiyi-st" id="yiyi-121">每个线程对象必须只能调用它一次。</span><span class="yiyi-st" id="yiyi-122">它为对象的<a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法在一个单独的控制线程中调用做准备。</span></p><p><span class="yiyi-st" id="yiyi-123">在相同的线程对象上调用该方法多次将引发一个<a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span></p></dd></dl><dl class="method"><dt id="threading.Thread.run"><span class="yiyi-st" id="yiyi-124"> <code class="descname">run</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-125">表示线程活动的方法。</span></p><p><span class="yiyi-st" id="yiyi-126">你可以在子类中覆盖这个方法。</span><span class="yiyi-st" id="yiyi-127">标准的<a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法调用传递给对象构造函数<em>target</em>参数的可调用对象,如果存在,分别从<em>args</em><em>kwargs</em>参数获取顺序参数和关键字参数。</span></p></dd></dl><dl class="method"><dt id="threading.Thread.join"><span class="yiyi-st" id="yiyi-128"> <code class="descname">join</code><span class="sig-paren">(</span><em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-129">等待直至线程终止。</span><span class="yiyi-st" id="yiyi-130">这将阻塞调用线程,直到调用<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>方法的线程终止(通常或通过未处理的异常),或直到可选超时发生。</span></p><p><span class="yiyi-st" id="yiyi-131"><em>timeout</em>参数存在且不为<code class="docutils literal"><span class="pre">None</span></code>时,它应该以一个浮点数指定该操作的超时时间,单位为秒(可以是小数)。</span><span class="yiyi-st" id="yiyi-132">由于<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>总是返回<code class="docutils literal"><span class="pre">None</span></code>,必须在调用<a class="reference internal" href="#threading.Thread.is_alive" title="threading.Thread.is_alive"><code class="xref py py-meth docutils literal"><span class="pre">is_alive()</span></code></a>之后来<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>决定是否发生超时 - 如果线程仍然存在,则<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>调用超时。</span></p><p><span class="yiyi-st" id="yiyi-133">如果<em>timeout</em>参数不存在或者为<code class="docutils literal"><span class="pre">None</span></code>,那么该操作将阻塞直至线程终止。</span></p><p><span class="yiyi-st" id="yiyi-134">一个线程可以被<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>多次。</span></p><p><span class="yiyi-st" id="yiyi-135">如果尝试join当前的线程<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>会引发一个<a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a>,因为这将导致一个死锁。</span><span class="yiyi-st" id="yiyi-136">它也是一个错误,<a class="reference internal" href="#threading.Thread.join" title="threading.Thread.join"><code class="xref py py-meth docutils literal"><span class="pre">join()</span></code></a>一个线程之前,它已经开始,并尝试这样做引发相同的异常。</span></p></dd></dl><dl class="attribute"><dt id="threading.Thread.name"><span class="yiyi-st" id="yiyi-137"> <code class="descname">name</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-138">一个字符串,只用于标识的目的。</span><span class="yiyi-st" id="yiyi-139">它没有语义。</span><span class="yiyi-st" id="yiyi-140">多个线程可以被赋予相同的名字。</span><span class="yiyi-st" id="yiyi-141">初始的名字通过构造函数设置。</span></p></dd></dl><dl class="method"><dt id="threading.Thread.getName"><span class="yiyi-st" id="yiyi-142"> <code class="descname">getName</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dt id="threading.Thread.setName"><span class="yiyi-st" id="yiyi-143"> <code class="descname">setName</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-144"><a class="reference internal" href="#threading.Thread.name" title="threading.Thread.name"><code class="xref py py-attr docutils literal"><span class="pre">name</span></code></a> 旧式的getter/setter API请直接以属性使用它。</span></p></dd></dl><dl class="attribute"><dt id="threading.Thread.ident"><span class="yiyi-st" id="yiyi-145"> <code class="descname">ident</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-146">线程的ID如果线程还未启动则为<code class="docutils literal"><span class="pre">None</span></code></span><span class="yiyi-st" id="yiyi-147">它是一个非零的整数。</span><span class="yiyi-st" id="yiyi-148">请参见<a class="reference internal" href="_thread.html#_thread.get_ident" title="_thread.get_ident"><code class="xref py py-func docutils literal"><span class="pre">_thread.get_ident()</span></code></a>函数。</span><span class="yiyi-st" id="yiyi-149">当一个线程退出另外一个线程创建时线程的ID可以重用。</span><span class="yiyi-st" id="yiyi-150">即使在线程退出后其ID仍然可以访问。</span></p></dd></dl><dl class="method"><dt id="threading.Thread.is_alive"><span class="yiyi-st" id="yiyi-151"> <code class="descname">is_alive</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-152">返回线程是否还活着。</span></p><p><span class="yiyi-st" id="yiyi-153"><a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法刚开始之前至<a class="reference internal" href="#threading.Thread.run" title="threading.Thread.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a>方法刚终止之后,该方法返回<code class="docutils literal"><span class="pre">True</span></code></span><span class="yiyi-st" id="yiyi-154">模块级别的函数<a class="reference internal" href="#threading.enumerate" title="threading.enumerate"><code class="xref py py-func docutils literal"><span class="pre">enumerate()</span></code></a>返回所有活着的函数的一个列表。</span></p></dd></dl><dl class="attribute"><dt id="threading.Thread.daemon"><span class="yiyi-st" id="yiyi-155"> <code class="descname">daemon</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-156">布尔值,该值指示是否此线程一个守护进程线程 (True),或不 (False)。</span><span class="yiyi-st" id="yiyi-157">它必须在调用 <a class="reference internal" href="#threading.Thread.start" title="threading.Thread.start"><code class="xref py py-meth docutils literal"><span class="pre">start()</span></code></a> 之前设置,否则引发 <a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span><span class="yiyi-st" id="yiyi-158">从创建的线程继承其初始的值,主线程不是守护线程,因此在主线程创建的所有线程的默认 <a class="reference internal" href="#threading.Thread.daemon" title="threading.Thread.daemon"><code class="xref py py-attr docutils literal"><span class="pre">daemon</span></code></a> = <code class="docutils literal"><span class="pre">False</span></code></span></p><p><span class="yiyi-st" id="yiyi-159">整个的 Python 程序在没有活着的非守护程序线程运行时退出。</span></p></dd></dl><dl class="method"><dt id="threading.Thread.isDaemon"><span class="yiyi-st" id="yiyi-160"> <code class="descname">isDaemon</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dt id="threading.Thread.setDaemon"><span class="yiyi-st" id="yiyi-161"> <code class="descname">setDaemon</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-162"><a class="reference internal" href="#threading.Thread.daemon" title="threading.Thread.daemon"><code class="xref py py-attr docutils literal"><span class="pre">daemon</span></code></a>的旧式getter/setter API现在请直接以属性使用它。</span></p></dd></dl></dd></dl><div class="impl-detail compound"><p><span class="yiyi-st" id="yiyi-163"><strong>CPython实现细节</strong>在CPython中由于<a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">Global Interpreter Lock</span></a>只有一个线程可以一次执行Python代码即使某些基于性能的库可能克服这个限制</span><span class="yiyi-st" id="yiyi-164">如果希望应用程序更好地利用多核机器的计算资源,建议使用<a class="reference internal" href="multiprocessing.html#module-multiprocessing" title="multiprocessing: Process-based parallelism."><code class="xref py py-mod docutils literal"><span class="pre">multiprocessing</span></code></a><a class="reference internal" href="concurrent.futures.html#concurrent.futures.ProcessPoolExecutor" title="concurrent.futures.ProcessPoolExecutor"><code class="xref py py-class docutils literal"><span class="pre">concurrent.futures.ProcessPoolExecutor</span></code></a></span><span class="yiyi-st" id="yiyi-165">然而如果你想并发地运行多个I/O密集的任务threading仍然是一个合适的模型。</span></p></div></div><div class="section" id="lock-objects"><h2><span class="yiyi-st" id="yiyi-166">17.1.3. </span><span class="yiyi-st" id="yiyi-167">Lock 对象</span></h2><p><span class="yiyi-st" id="yiyi-168">原锁是一个同步原语,当它锁住时不归某个特定的线程所有。</span><span class="yiyi-st" id="yiyi-169">在Python中它是当前可用的最低级同步原语<a class="reference internal" href="_thread.html#module-_thread" title="_thread: Low-level threading API."><code class="xref py py-mod docutils literal"><span class="pre">_thread</span></code></a> 扩展模块直接实现。</span></p><p><span class="yiyi-st" id="yiyi-170">一个原锁处于“locked”或者“unlocked”状态中的一种。</span><span class="yiyi-st" id="yiyi-171">它创建时处于unlocked状态。</span><span class="yiyi-st" id="yiyi-172">它有两个基本方法,<a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a><a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a></span><span class="yiyi-st" id="yiyi-173">当状态是unlocked时<a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a>改变该状态为locked并立即返回。</span><span class="yiyi-st" id="yiyi-174">当状态是 locked 时,<a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a> 阻塞,直到在另一个线程中对 <a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> 的调用将其改为 unlocked然后 <a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a> 调用重新设置它为 locked 并返回。</span><span class="yiyi-st" id="yiyi-175"><a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> 方法只应在 locked 状态下调用;它将状态更改为 unlocked 并立即返回。</span><span class="yiyi-st" id="yiyi-176">如果尝试释放 unlocked 的锁,将会引发 <a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-177">Locks 还支持 <a class="reference internal" href="#with-locks"><span>上下文管理器协议</span></a></span></p><p><span class="yiyi-st" id="yiyi-178">当有多个线程被 <a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a> 阻塞,等待状态变为 unlocked 时,只有一个线程在 <a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> 调用将状态重置为 unlocked 时可以继续;等待线程中的哪一个继续未被定义,并且在不同的实现中可能不一致。</span></p><p><span class="yiyi-st" id="yiyi-179">所有方法的执行都是原子的。</span></p><dl class="class"><dt id="threading.Lock"><span class="yiyi-st" id="yiyi-180"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Lock</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-181">实现原语锁对象的类。</span><span class="yiyi-st" id="yiyi-182">一旦线程获得锁,随后的获取它的尝试阻塞,直到它被释放;任何线程都可以释放它。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-183"><span class="versionmodified">在版本3.3中更改:</span>从工厂函数更改为类。</span></p></div><dl class="method"><dt id="threading.Lock.acquire"><span class="yiyi-st" id="yiyi-184"> <code class="descname">acquire</code><span class="sig-paren">(</span><em>blocking=True</em>, <em>timeout=-1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-185">获取一把锁,阻塞的或者非阻塞的。</span></p><p><span class="yiyi-st" id="yiyi-186">当调用时 <em>blocking</em> 参数设置为<code class="docutils literal"><span class="pre">True</span></code>(默认值),将阻塞直至锁变成 unblocked然后设置它的状态为locked并返回 <code class="docutils literal"><span class="pre">True</span></code></span></p><p><span class="yiyi-st" id="yiyi-187">当调用时 <em>blocking</em> 参数设置为 <code class="docutils literal"><span class="pre">False</span></code>,将不会阻塞。</span><span class="yiyi-st" id="yiyi-188">如果 <em>blocking</em> 设置为<code class="docutils literal"><span class="pre">True</span></code> 的调用将被阻止,请立即返回<code class="docutils literal"><span class="pre">False</span></code>;否则,将锁定设置为锁定并返回<code class="docutils literal"><span class="pre">True</span></code></span></p><p><span class="yiyi-st" id="yiyi-189">当浮点<em>超时</em>参数设置为正值时调用时,最多只能阻塞<em>timeout</em>指定的秒数,只要无法获取锁定。</span><span class="yiyi-st" id="yiyi-190"><code class="docutils literal"><span class="pre">-1</span></code><em>timeout</em>参数指定无界等待。</span><span class="yiyi-st" id="yiyi-191"><em>阻止</em>为false时禁止指定<em>超时</em></span></p><p><span class="yiyi-st" id="yiyi-192">如果成功获取锁定,则返回值为<code class="docutils literal"><span class="pre">True</span></code>,如果未成功,则返回<code class="docutils literal"><span class="pre">False</span></code>(例如,如果<em>超时</em>过期)。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-193"><span class="versionmodified">版本3.2中的变化:</span> 新增 <em>timeout </em> 参数。</span></p></div><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-194"><span class="versionmodified">在版本3.2中更改:</span>锁获取现在可以被POSIX上的信号中断。</span></p></div></dd></dl><dl class="method"><dt id="threading.Lock.release"><span class="yiyi-st" id="yiyi-195"> <code class="descname">release</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-196">释放一把锁。</span><span class="yiyi-st" id="yiyi-197">这可以从任何线程调用,而不仅仅是已经获得锁的线程。</span></p><p><span class="yiyi-st" id="yiyi-198">当锁是locked时重置它为unlocked然后返回。</span><span class="yiyi-st" id="yiyi-199">如果存在其他阻塞的线程正在等待锁变成unblocked状态只会允许它们中的一个继续。</span></p><p><span class="yiyi-st" id="yiyi-200">当在未锁定的锁上调用时,会引发<a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-201">没有返回值。</span></p></dd></dl></dd></dl></div><div class="section" id="rlock-objects"><h2><span class="yiyi-st" id="yiyi-202">17.1.4. </span><span class="yiyi-st" id="yiyi-203">RLock 对象</span></h2><p><span class="yiyi-st" id="yiyi-204">一个可重入所示一个同步原语,它可以被相同的线程获得多次。</span><span class="yiyi-st" id="yiyi-205">Internally, it uses the concepts of “owning thread” and “recursion level” in addition to the locked/unlocked state used by primitive locks. </span><span class="yiyi-st" id="yiyi-206">在锁定状态下,一些线程拥有锁;在解锁状态下,没有线程拥有它。</span></p><p><span class="yiyi-st" id="yiyi-207">要锁定锁,线程调用其<a class="reference internal" href="#threading.RLock.acquire" title="threading.RLock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a>方法;这个返回一旦线程拥有锁。</span><span class="yiyi-st" id="yiyi-208">To unlock the lock, a thread calls its <a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> method. </span><span class="yiyi-st" id="yiyi-209"><a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a> / <a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>调用对可以嵌套;只有最后的<a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>(最外面的对的<a class="reference internal" href="#threading.Lock.release" title="threading.Lock.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>)将锁重置为已解锁并允许另一个线程在<a class="reference internal" href="#threading.Lock.acquire" title="threading.Lock.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-210">可重入锁也支持<a class="reference internal" href="#with-locks"><span>上下文管理器协议</span></a></span></p><dl class="class"><dt id="threading.RLock"><span class="yiyi-st" id="yiyi-211"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">RLock</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-212">此类实现可重入锁定对象。</span><span class="yiyi-st" id="yiyi-213">一个可重入锁必须由获得它的线程释放。</span><span class="yiyi-st" id="yiyi-214">一旦线程获得了可重入锁,同一线程可以再次获取它而不阻塞;线程必须每次释放它一次它已经获得它。</span></p><p><span class="yiyi-st" id="yiyi-215">注意,<code class="docutils literal"><span class="pre">RLock</span></code>实际上是一个工厂函数它返回平台支持的具体RLock类的最高效版本的实例。</span></p><dl class="method"><dt id="threading.RLock.acquire"><span class="yiyi-st" id="yiyi-216"> <code class="descname">acquire</code><span class="sig-paren">(</span><em>blocking=True</em>, <em>timeout=-1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-217">获取一把锁,阻塞的或者非阻塞的。</span></p><p><span class="yiyi-st" id="yiyi-218">When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. </span><span class="yiyi-st" id="yiyi-219">Otherwise, if another thread owns the lock, block until the lock is unlocked. </span><span class="yiyi-st" id="yiyi-220">Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. </span><span class="yiyi-st" id="yiyi-221">If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. </span><span class="yiyi-st" id="yiyi-222">There is no return value in this case.</span></p><p><span class="yiyi-st" id="yiyi-223">When invoked with the <em>blocking</em> argument set to true, do the same thing as when called without arguments, and return true.</span></p><p><span class="yiyi-st" id="yiyi-224">When invoked with the <em>blocking</em> argument set to false, do not block. </span><span class="yiyi-st" id="yiyi-225">如果没有参数的调用将阻塞立即返回false否则做与没有参数调用时相同的事情并返回true。</span></p><p><span class="yiyi-st" id="yiyi-226">当浮点<em>超时</em>参数设置为正值时调用时,最多只能阻塞<em>timeout</em>指定的秒数,只要无法获取锁定。</span><span class="yiyi-st" id="yiyi-227">如果已获取锁定则返回true如果超时已过则返回false。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-228"><span class="versionmodified">在版本3.2中更改:</span> <em>超时</em>参数是新的。</span></p></div></dd></dl><dl class="method"><dt id="threading.RLock.release"><span class="yiyi-st" id="yiyi-229"> <code class="descname">release</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-230">Release a lock, decrementing the recursion level. </span><span class="yiyi-st" id="yiyi-231">If after the decrement it is zero, reset the lock to unlocked (not owned by any thread), and if any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed. </span><span class="yiyi-st" id="yiyi-232">If after the decrement the recursion level is still nonzero, the lock remains locked and owned by the calling thread.</span></p><p><span class="yiyi-st" id="yiyi-233">Only call this method when the calling thread owns the lock. </span><span class="yiyi-st" id="yiyi-234">A <a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a> is raised if this method is called when the lock is unlocked.</span></p><p><span class="yiyi-st" id="yiyi-235">没有返回值。</span></p></dd></dl></dd></dl></div><div class="section" id="condition-objects"><h2><span class="yiyi-st" id="yiyi-236">17.1.5. </span><span class="yiyi-st" id="yiyi-237">Condition 对象</span></h2><p><span class="yiyi-st" id="yiyi-238">Condition 变量总是与某种锁相关联;这个锁可以传入,否则将默认创建一个锁。</span><span class="yiyi-st" id="yiyi-239">传递一个锁进去主要用于几个 Condition 变量必须共享同一个锁的时候。</span><span class="yiyi-st" id="yiyi-240">锁是 Condition 对象的一部分:你不必单独跟踪它。</span></p><p><span class="yiyi-st" id="yiyi-241">Condition 变量遵守<a class="reference internal" href="#with-locks"><span>上下文管理器协议</span></a>:使用 <code class="docutils literal"><span class="pre">with</span></code> 语句获取关联的锁用于包围的语句块。</span><span class="yiyi-st" id="yiyi-242"><a class="reference internal" href="#threading.Condition.acquire" title="threading.Condition.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a><a class="reference internal" href="#threading.Condition.release" title="threading.Condition.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>方法也调用相关锁的相应方法。</span></p><p><span class="yiyi-st" id="yiyi-243">其他方法必须调用相关锁持有。</span><span class="yiyi-st" id="yiyi-244"><a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>方法释放锁,然后阻塞,直到另一个线程通过调用<a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a><a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a>唤醒它。</span><span class="yiyi-st" id="yiyi-245">一旦被唤醒,<a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>重新获取锁并返回。</span><span class="yiyi-st" id="yiyi-246">It is also possible to specify a timeout.</span></p><p><span class="yiyi-st" id="yiyi-247">如果有正在等待的线程,<a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a> 方法唤醒等待 Condition 变量的其中一个线程。</span><span class="yiyi-st" id="yiyi-248"><a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a> 方法唤醒所有等待这个 Condition 变量的线程。</span></p><p><span class="yiyi-st" id="yiyi-249">注意:<a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a><a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a> 方法不释放锁;这意味着唤醒的一个线程或多个线程不会立即从其 <a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> 调用返回,而只有当调用 <a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a><a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a> 的线程最终放弃锁的所有权。</span></p><p><span class="yiyi-st" id="yiyi-250">The typical programming style using condition variables uses the lock to synchronize access to some shared state; threads that are interested in a particular change of state call <a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> repeatedly until they see the desired state, while threads that modify the state call <a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a> or <a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a> when they change the state in such a way that it could possibly be a desired state for one of the waiters. </span><span class="yiyi-st" id="yiyi-251">For example, the following code is a generic producer-consumer situation with unlimited buffer capacity:</span></p><pre><code class="language-python"><span></span><span class="c1"># Consume one item</span>
<span class="k">with</span> <span class="n">cv</span><span class="p">:</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">an_item_is_available</span><span class="p">():</span>
<span class="n">cv</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="n">get_an_available_item</span><span class="p">()</span>
<span class="c1"># Produce one item</span>
<span class="k">with</span> <span class="n">cv</span><span class="p">:</span>
<span class="n">make_an_item_available</span><span class="p">()</span>
<span class="n">cv</span><span class="o">.</span><span class="n">notify</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-252"><code class="docutils literal"><span class="pre">while</span></code> 循环检查应用程序的条件是必要的,因为 <a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> 可能在任意长时间后返回,并且发出 <a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a> 的 Condition 可能不再持有锁。</span><span class="yiyi-st" id="yiyi-253">这是多线程编程固有的。</span><span class="yiyi-st" id="yiyi-254"><a class="reference internal" href="#threading.Condition.wait_for" title="threading.Condition.wait_for"><code class="xref py py-meth docutils literal"><span class="pre">wait_for()</span></code></a>方法可用于自动进行条件检查,并减少超时计算:</span></p><pre><code class="language-python"><span></span><span class="c1"># Consume an item</span>
<span class="k">with</span> <span class="n">cv</span><span class="p">:</span>
<span class="n">cv</span><span class="o">.</span><span class="n">wait_for</span><span class="p">(</span><span class="n">an_item_is_available</span><span class="p">)</span>
<span class="n">get_an_available_item</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-255">要在<a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a><a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a>之间进行选择,请考虑一个状态更改是否只对一个或多个等待线程感兴趣。</span><span class="yiyi-st" id="yiyi-256">例如,</span><span class="yiyi-st" id="yiyi-257">在典型的生产者-消费者情形中,向缓存添加一个条目仅需要唤醒一个消费者线程。</span></p><dl class="class"><dt id="threading.Condition"><span class="yiyi-st" id="yiyi-258"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Condition</code><span class="sig-paren">(</span><em>lock=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-259">这个类实现条件变量对象。</span><span class="yiyi-st" id="yiyi-260">一个条件变量允许一个或多个线程等待直至它们收到另外一个线程的通知。</span></p><p><span class="yiyi-st" id="yiyi-261">如果给出 <em>lock</em> 参数且不是 <code class="docutils literal"><span class="pre">None</span></code>,则它必须是 <a class="reference internal" href="#threading.Lock" title="threading.Lock"><code class="xref py py-class docutils literal"><span class="pre">Lock</span></code></a><a class="reference internal" href="#threading.RLock" title="threading.RLock"><code class="xref py py-class docutils literal"><span class="pre">RLock</span></code></a> 对象,它用作底层的锁。</span><span class="yiyi-st" id="yiyi-262">否则,将创建一个新的 <a class="reference internal" href="#threading.RLock" title="threading.RLock"><code class="xref py py-class docutils literal"><span class="pre">RLock</span></code></a> 对象并将其用作底层的锁。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-263"><span class="versionmodified">在版本3.3中更改:</span>从工厂函数更改为类。</span></p></div><dl class="method"><dt id="threading.Condition.acquire"><span class="yiyi-st" id="yiyi-264"> <code class="descname">acquire</code><span class="sig-paren">(</span><em>*args</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-265">获取底层锁。</span><span class="yiyi-st" id="yiyi-266">这个方法调用底层锁的相应方法;返回值是该方法返回的任何值。</span></p></dd></dl><dl class="method"><dt id="threading.Condition.release"><span class="yiyi-st" id="yiyi-267"> <code class="descname">release</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-268">释放底层锁。</span><span class="yiyi-st" id="yiyi-269">这个方法调用底层锁的相应方法;没有返回值。</span></p></dd></dl><dl class="method"><dt id="threading.Condition.wait"><span class="yiyi-st" id="yiyi-270"> <code class="descname">wait</code><span class="sig-paren">(</span><em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-271">等待直到收到通知或直到发生超时。</span><span class="yiyi-st" id="yiyi-272">如果调用此方法时调用线程尚未获取锁,则引发 <a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-273">这种方法释放底层锁,然后阻塞,直到它被一个在另一个线程中调用相同 Condition 变量的 <a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a><a class="reference internal" href="#threading.Condition.notify_all" title="threading.Condition.notify_all"><code class="xref py py-meth docutils literal"><span class="pre">notify_all()</span></code></a> 唤醒,或直到超时。</span><span class="yiyi-st" id="yiyi-274">一旦被唤醒或超时,它就会重新获得锁定并返回。</span></p><p><span class="yiyi-st" id="yiyi-275"><em>timeout</em> 参数存在而不是<code class="docutils literal"><span class="pre">None</span></code>时,它应该是一个浮点数,指定操作的超时(以秒为单位)(或其分数)。</span></p><p><span class="yiyi-st" id="yiyi-276">当底层的锁是 <a class="reference internal" href="#threading.RLock" title="threading.RLock"><code class="xref py py-class docutils literal"><span class="pre">RLock</span></code></a> 时,它不会使用其 <a class="reference internal" href="#threading.Condition.release" title="threading.Condition.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> 方法释放,因为当它以递归方式多次获取时,实际上可能无法解锁。</span><span class="yiyi-st" id="yiyi-277">相反,使用了 <a class="reference internal" href="#threading.RLock" title="threading.RLock"><code class="xref py py-class docutils literal"><span class="pre">RLock</span></code></a> 类的内部接口,即使多次递归获取它也能解锁它。</span><span class="yiyi-st" id="yiyi-278">然后,在重新获取锁时,使用另一个内部接口来恢复递归级别。</span></p><p><span class="yiyi-st" id="yiyi-279">返回值为 <code class="docutils literal"><span class="pre">True</span></code>,除非给定的 <em>timeout</em> 过期,在这种情况下为 <code class="docutils literal"><span class="pre">False</span></code></span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-280"><span class="versionmodified">在版本3.2中更改:</span>以前,该方法始终返回<code class="docutils literal"><span class="pre">None</span></code></span></p></div></dd></dl><dl class="method"><dt id="threading.Condition.wait_for"><span class="yiyi-st" id="yiyi-281"> <code class="descname">wait_for</code><span class="sig-paren">(</span><em>predicate</em>, <em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-282">等待条件的计算结果为True。</span><span class="yiyi-st" id="yiyi-283"><em>predicate</em> 应为一个可调用对象,其结果将被解释为布尔值。</span><span class="yiyi-st" id="yiyi-284">可以提供 <em>timeout</em>,给出最大等待时间。</span></p><p><span class="yiyi-st" id="yiyi-285">这个方法可能会重复调用<a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>直到满足predicate或直到发生超时。</span><span class="yiyi-st" id="yiyi-286">返回值是 predicate 的最后一个返回值,如果方法超时,则求值为 <code class="docutils literal"><span class="pre">False</span></code></span></p><p><span class="yiyi-st" id="yiyi-287">忽略超时功能,调用此方法大致相当于编写:</span></p><pre><code class="language-python"><span></span><span class="k">while</span> <span class="ow">not</span> <span class="n">predicate</span><span class="p">():</span>
<span class="n">cv</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-288">因此,与 <a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> 一样适用相同的规则:必须在调用时保持锁定并在返回时重新获取。</span><span class="yiyi-st" id="yiyi-289">predicate是在加锁的情况下进行计算。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-290"><span class="versionmodified">版本3.2中的新功能。</span></span></p></div></dd></dl><dl class="method"><dt id="threading.Condition.notify"><span class="yiyi-st" id="yiyi-291"> <code class="descname">notify</code><span class="sig-paren">(</span><em>n=1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-292">默认情况下,唤醒一个等待此 Condition 的线程(如果有)。</span><span class="yiyi-st" id="yiyi-293">如果调用此方法时调用线程尚未获取到锁,则引发 <a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-294">该方法最多唤醒等待这个 Condiction 变量的 <em>n</em> 个线程;如果没有线程正在等待,则它是一个无操作。</span></p><p><span class="yiyi-st" id="yiyi-295">The current implementation wakes up exactly <em>n</em> threads, if at least <em>n</em> threads are waiting. </span><span class="yiyi-st" id="yiyi-296">However, its not safe to rely on this behavior. </span><span class="yiyi-st" id="yiyi-297">A future, optimized implementation may occasionally wake up more than <em>n</em> threads.</span></p><p><span class="yiyi-st" id="yiyi-298">注意:唤醒的线程实际上不会从其 <a class="reference internal" href="#threading.Condition.wait" title="threading.Condition.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> 调用返回,直到它可以重新获取锁定。</span><span class="yiyi-st" id="yiyi-299">由于 <a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a> 不释放锁,因此其调用者应该释放。</span></p></dd></dl><dl class="method"><dt id="threading.Condition.notify_all"><span class="yiyi-st" id="yiyi-300"> <code class="descname">notify_all</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-301">Wake up all threads waiting on this condition. </span><span class="yiyi-st" id="yiyi-302">This method acts like <a class="reference internal" href="#threading.Condition.notify" title="threading.Condition.notify"><code class="xref py py-meth docutils literal"><span class="pre">notify()</span></code></a>, but wakes up all waiting threads instead of one. </span><span class="yiyi-st" id="yiyi-303">If the calling thread has not acquired the lock when this method is called, a <a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a> is raised.</span></p></dd></dl></dd></dl></div><div class="section" id="semaphore-objects"><h2><span class="yiyi-st" id="yiyi-304">17.1.6. </span><span class="yiyi-st" id="yiyi-305">Semaphore 对象</span></h2><p><span class="yiyi-st" id="yiyi-306">This is one of the oldest synchronization primitives in the history of computer science, invented by the early Dutch computer scientist Edsger W. Dijkstra (he used the names <code class="docutils literal"><span class="pre">P()</span></code> and <code class="docutils literal"><span class="pre">V()</span></code> instead of <a class="reference internal" href="#threading.Semaphore.acquire" title="threading.Semaphore.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a> and <a class="reference internal" href="#threading.Semaphore.release" title="threading.Semaphore.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>).</span></p><p><span class="yiyi-st" id="yiyi-307">信号量管理内部计数器,每个<a class="reference internal" href="#threading.Semaphore.acquire" title="threading.Semaphore.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a>调用递减,每个<a class="reference internal" href="#threading.Semaphore.release" title="threading.Semaphore.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>调用递增。</span><span class="yiyi-st" id="yiyi-308">计数器永远不会低于零;当<a class="reference internal" href="#threading.Semaphore.acquire" title="threading.Semaphore.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a>发现它为零时,它阻塞,等待其他线程调用<a class="reference internal" href="#threading.Semaphore.release" title="threading.Semaphore.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-309">Semaphores还支持<a class="reference internal" href="#with-locks"><span>context management protocol</span></a></span></p><dl class="class"><dt id="threading.Semaphore"><span class="yiyi-st" id="yiyi-310"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Semaphore</code><span class="sig-paren">(</span><em>value=1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-311">这个类实现了信号量对象。</span><span class="yiyi-st" id="yiyi-312">信号量管理表示<a class="reference internal" href="#threading.Semaphore.release" title="threading.Semaphore.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a>调用数减去<a class="reference internal" href="#threading.Semaphore.acquire" title="threading.Semaphore.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a>调用数加上一个初始值的计数器。</span><span class="yiyi-st" id="yiyi-313"><a class="reference internal" href="#threading.Semaphore.acquire" title="threading.Semaphore.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a>方法将会阻塞直到它可以在返回时计数器不是负数。</span><span class="yiyi-st" id="yiyi-314">如果没有给出,<em>value</em>默认为1。</span></p><p><span class="yiyi-st" id="yiyi-315">可选参数给出内部计数器的初始<em></em>;它默认为<code class="docutils literal"><span class="pre">1</span></code></span><span class="yiyi-st" id="yiyi-316">If the <em>value</em> given is less than 0, <a class="reference internal" href="exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal"><span class="pre">ValueError</span></code></a> is raised.</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-317"><span class="versionmodified">在版本3.3中更改:</span>从工厂函数更改为类。</span></p></div><dl class="method"><dt id="threading.Semaphore.acquire"><span class="yiyi-st" id="yiyi-318"> <code class="descname">acquire</code><span class="sig-paren">(</span><em>blocking=True</em>, <em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-319">Acquire a semaphore.</span></p><p><span class="yiyi-st" id="yiyi-320">When invoked without arguments: if the internal counter is larger than zero on entry, decrement it by one and return immediately. </span><span class="yiyi-st" id="yiyi-321">If it is zero on entry, block, waiting until some other thread has called <a class="reference internal" href="#threading.Semaphore.release" title="threading.Semaphore.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> to make it larger than zero. </span><span class="yiyi-st" id="yiyi-322">This is done with proper interlocking so that if multiple <a class="reference internal" href="#threading.Semaphore.acquire" title="threading.Semaphore.acquire"><code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code></a> calls are blocked, <a class="reference internal" href="#threading.Semaphore.release" title="threading.Semaphore.release"><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></a> will wake exactly one of them up. </span><span class="yiyi-st" id="yiyi-323">The implementation may pick one at random, so the order in which blocked threads are awakened should not be relied on. </span><span class="yiyi-st" id="yiyi-324">返回true或无限期块</span></p><p><span class="yiyi-st" id="yiyi-325">When invoked with <em>blocking</em> set to false, do not block. </span><span class="yiyi-st" id="yiyi-326">如果没有参数的调用将阻塞立即返回false否则做与没有参数调用时相同的事情并返回true。</span></p><p><span class="yiyi-st" id="yiyi-327">当以<em>超时</em>调用非None时它将至多阻止<em>超时</em>秒。</span><span class="yiyi-st" id="yiyi-328">如果在该时间间隔内未成功完成捕获则返回false。</span><span class="yiyi-st" id="yiyi-329">否则返回true。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-330"><span class="versionmodified">在版本3.2中更改:</span> <em>超时</em>参数是新的。</span></p></div></dd></dl><dl class="method"><dt id="threading.Semaphore.release"><span class="yiyi-st" id="yiyi-331"> <code class="descname">release</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-332">Release a semaphore, incrementing the internal counter by one. </span><span class="yiyi-st" id="yiyi-333">When it was zero on entry and another thread is waiting for it to become larger than zero again, wake up that thread.</span></p></dd></dl></dd></dl><dl class="class"><dt id="threading.BoundedSemaphore"><span class="yiyi-st" id="yiyi-334"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">BoundedSemaphore</code><span class="sig-paren">(</span><em>value=1</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-335">类实现有界信号对象。</span><span class="yiyi-st" id="yiyi-336">一个有界信号量会确保它当前的值不超过它的初始值。</span><span class="yiyi-st" id="yiyi-337">如果超过,则引发<a class="reference internal" href="exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal"><span class="pre">ValueError</span></code></a></span><span class="yiyi-st" id="yiyi-338">在大部分情况下,信号量用于守护有限容量的资源。</span><span class="yiyi-st" id="yiyi-339">如果信号量被释放太多次它是一种有bug的迹象。</span><span class="yiyi-st" id="yiyi-340">如果没有给出,<em>value</em>默认为1。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-341"><span class="versionmodified">在版本3.3中更改:</span>从工厂函数更改为类。</span></p></div></dd></dl><div class="section" id="semaphore-example"><h3><span class="yiyi-st" id="yiyi-342">17.1.6.1. </span><span class="yiyi-st" id="yiyi-343"><a class="reference internal" href="#threading.Semaphore" title="threading.Semaphore"><code class="xref py py-class docutils literal"><span class="pre">Semaphore</span></code></a> Example</span></h3><p><span class="yiyi-st" id="yiyi-344">Semaphores are often used to guard resources with limited capacity, for example, a database server. </span><span class="yiyi-st" id="yiyi-345">In any situation where the size of the resource is fixed, you should use a bounded semaphore. </span><span class="yiyi-st" id="yiyi-346">Before spawning any worker threads, your main thread would initialize the semaphore:</span></p><pre><code class="language-python"><span></span><span class="n">maxconnections</span> <span class="o">=</span> <span class="mi">5</span>
<span class="c1"># ...</span>
<span class="n">pool_sema</span> <span class="o">=</span> <span class="n">BoundedSemaphore</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="n">maxconnections</span><span class="p">)</span>
</code></pre><p><span class="yiyi-st" id="yiyi-347">Once spawned, worker threads call the semaphores acquire and release methods when they need to connect to the server:</span></p><pre><code class="language-python"><span></span><span class="k">with</span> <span class="n">pool_sema</span><span class="p">:</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">connectdb</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># ... use connection ...</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-348">The use of a bounded semaphore reduces the chance that a programming error which causes the semaphore to be released more than its acquired will go undetected.</span></p></div></div><div class="section" id="event-objects"><h2><span class="yiyi-st" id="yiyi-349">17.1.7. </span><span class="yiyi-st" id="yiyi-350">Event Objects</span></h2><p><span class="yiyi-st" id="yiyi-351">事件对象是线程间最简单的通信机制之一:线程可以激活在一个事件对象上等待的其他线程</span></p><p><span class="yiyi-st" id="yiyi-352">每个事件对象管理一个内部标志,可以在事件对象上调用<a class="reference internal" href="#threading.Event.set" title="threading.Event.set"><code class="xref py py-meth docutils literal"><span class="pre">set()</span></code></a> 方法将内部标志设为true调用 <a class="reference internal" href="#threading.Event.clear" title="threading.Event.clear"><code class="xref py py-meth docutils literal"><span class="pre">clear()</span></code></a> 方法将内部标志重置为false。</span><span class="yiyi-st" id="yiyi-353"><a class="reference internal" href="#threading.Event.wait" title="threading.Event.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>方法将阻塞直至该标志为真。</span></p><dl class="class"><dt id="threading.Event"><span class="yiyi-st" id="yiyi-354"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Event</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-355">实现事件对象的类。</span><span class="yiyi-st" id="yiyi-356">一个event管理一个标志该标志可以通过<a class="reference internal" href="#threading.Event.set" title="threading.Event.set"><code class="xref py py-meth docutils literal"><span class="pre">set()</span></code></a>方法设置为真或通过<a class="reference internal" href="#threading.Event.clear" title="threading.Event.clear"><code class="xref py py-meth docutils literal"><span class="pre">clear()</span></code></a>方法重新设置为假。</span><span class="yiyi-st" id="yiyi-357"><a class="reference internal" href="#threading.Event.wait" title="threading.Event.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>方法阻塞,直到标志为真。</span><span class="yiyi-st" id="yiyi-358">该标志最初为假。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-359"><span class="versionmodified">在版本3.3中更改:</span>从工厂函数更改为类。</span></p></div><dl class="method"><dt id="threading.Event.is_set"><span class="yiyi-st" id="yiyi-360"> <code class="descname">is_set</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-361">Return true if and only if the internal flag is true.</span></p></dd></dl><dl class="method"><dt id="threading.Event.set"><span class="yiyi-st" id="yiyi-362"> <code class="descname">set</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-363">Set the internal flag to true. </span><span class="yiyi-st" id="yiyi-364">All threads waiting for it to become true are awakened. </span><span class="yiyi-st" id="yiyi-365">Threads that call <a class="reference internal" href="#threading.Event.wait" title="threading.Event.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> once the flag is true will not block at all.</span></p></dd></dl><dl class="method"><dt id="threading.Event.clear"><span class="yiyi-st" id="yiyi-366"> <code class="descname">clear</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-367">Reset the internal flag to false. </span><span class="yiyi-st" id="yiyi-368">Subsequently, threads calling <a class="reference internal" href="#threading.Event.wait" title="threading.Event.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a> will block until <a class="reference internal" href="#threading.Event.set" title="threading.Event.set"><code class="xref py py-meth docutils literal"><span class="pre">set()</span></code></a> is called to set the internal flag to true again.</span></p></dd></dl><dl class="method"><dt id="threading.Event.wait"><span class="yiyi-st" id="yiyi-369"> <code class="descname">wait</code><span class="sig-paren">(</span><em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-370">Block until the internal flag is true. </span><span class="yiyi-st" id="yiyi-371">If the internal flag is true on entry, return immediately. </span><span class="yiyi-st" id="yiyi-372">Otherwise, block until another thread calls <a class="reference internal" href="#threading.Event.set" title="threading.Event.set"><code class="xref py py-meth docutils literal"><span class="pre">set()</span></code></a> to set the flag to true, or until the optional timeout occurs.</span></p><p><span class="yiyi-st" id="yiyi-373">When the timeout argument is present and not <code class="docutils literal"><span class="pre">None</span></code>, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).</span></p><p><span class="yiyi-st" id="yiyi-374">如果且仅当内部标志在等待调用之前或等待开始之后设置为true时此方法才返回true因此它将始终返回<code class="docutils literal"><span class="pre">True</span></code>,除非给出超时,并且操作超时。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-375"><span class="versionmodified">在版本3.1中更改:</span>以前,该方法始终返回<code class="docutils literal"><span class="pre">None</span></code></span></p></div></dd></dl></dd></dl></div><div class="section" id="timer-objects"><h2><span class="yiyi-st" id="yiyi-376">17.1.8. </span><span class="yiyi-st" id="yiyi-377">Timer Objects</span></h2><p><span class="yiyi-st" id="yiyi-378">这个类表示一个动作应该在一个特定的时间之后运行 — 也就是一个计时器。</span><span class="yiyi-st" id="yiyi-379"><a class="reference internal" href="#threading.Timer" title="threading.Timer"><code class="xref py py-class docutils literal"><span class="pre">Timer</span></code></a><a class="reference internal" href="#threading.Thread" title="threading.Thread"><code class="xref py py-class docutils literal"><span class="pre">Thread</span></code></a>的子类, 因此也可以使用函数创建自定义线程</span></p><p><span class="yiyi-st" id="yiyi-380">Timers通过调用它们的<code class="xref py py-meth docutils literal"><span class="pre">start()</span></code>方法作为线程启动。</span><span class="yiyi-st" id="yiyi-381">timer可以通过调用<a class="reference internal" href="#threading.Timer.cancel" title="threading.Timer.cancel"><code class="xref py py-meth docutils literal"><span class="pre">cancel()</span></code></a>方法(在它的动作开始之前)停止。</span><span class="yiyi-st" id="yiyi-382">timer在执行它的动作之前等待的时间间隔可能与用户指定的时间间隔不完全相同。</span></p><p><span class="yiyi-st" id="yiyi-383">例如:</span></p><pre><code class="language-python"><span></span><span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"hello, world"</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">Timer</span><span class="p">(</span><span class="mf">30.0</span><span class="p">,</span> <span class="n">hello</span><span class="p">)</span>
<span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> <span class="c1"># after 30 seconds, "hello, world" will be printed</span>
</code></pre><dl class="class"><dt id="threading.Timer"><span class="yiyi-st" id="yiyi-384"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Timer</code><span class="sig-paren">(</span><em>interval</em>, <em>function</em>, <em>args=None</em>, <em>kwargs=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-385">创建一个timer<em>interval</em>秒过去之后,它将以参数<em>args</em>和关键字参数<em>kwargs</em>运行<em>function</em></span><span class="yiyi-st" id="yiyi-386">如果<em>args</em>为None默认值则将使用空列表。</span><span class="yiyi-st" id="yiyi-387">如果<em>kwargs</em>为None默认值则将使用空的字典。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-388"><span class="versionmodified">在版本3.3中更改:</span>从工厂函数更改为类。</span></p></div><dl class="method"><dt id="threading.Timer.cancel"><span class="yiyi-st" id="yiyi-389"> <code class="descname">cancel</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-390">停止timer并取消timer动作的执行。</span><span class="yiyi-st" id="yiyi-391">这只在timer仍然处于等待阶段时才工作。</span></p></dd></dl></dd></dl></div><div class="section" id="barrier-objects"><h2><span class="yiyi-st" id="yiyi-392">17.1.9. </span><span class="yiyi-st" id="yiyi-393">Barrier Objects</span></h2><div class="versionadded"><p><span class="yiyi-st" id="yiyi-394"><span class="versionmodified">版本3.2中的新功能。</span></span></p></div><p><span class="yiyi-st" id="yiyi-395">这个类提供了一个简单的同步原语,供需要彼此等待的固定数量的线程使用。</span><span class="yiyi-st" id="yiyi-396">每个线程尝试通过调用<a class="reference internal" href="#threading.Barrier.wait" title="threading.Barrier.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>方法传递屏障,并将阻塞,直到所有线程都调用。</span><span class="yiyi-st" id="yiyi-397">在这一点上,线程被同时释放。</span></p><p><span class="yiyi-st" id="yiyi-398">对于相同数量的螺纹,可以重复使用任何次数的屏障。</span></p><p><span class="yiyi-st" id="yiyi-399">例如,下面是一个同步客户端和服务器线程的简单方法:</span></p><pre><code class="language-python"><span></span><span class="n">b</span> <span class="o">=</span> <span class="n">Barrier</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">server</span><span class="p">():</span>
<span class="n">start_server</span><span class="p">()</span>
<span class="n">b</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">connection</span> <span class="o">=</span> <span class="n">accept_connection</span><span class="p">()</span>
<span class="n">process_server_connection</span><span class="p">(</span><span class="n">connection</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">client</span><span class="p">():</span>
<span class="n">b</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">connection</span> <span class="o">=</span> <span class="n">make_connection</span><span class="p">()</span>
<span class="n">process_client_connection</span><span class="p">(</span><span class="n">connection</span><span class="p">)</span>
</code></pre><dl class="class"><dt id="threading.Barrier"><span class="yiyi-st" id="yiyi-400"> <em class="property">class </em><code class="descclassname">threading.</code><code class="descname">Barrier</code><span class="sig-paren">(</span><em>parties</em>, <em>action=None</em>, <em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-401"><em>参与方创建障碍对象</em>线程数。</span><span class="yiyi-st" id="yiyi-402">提供时,<em>操作</em>是可释放时由其中一个线程调用的调用。</span><span class="yiyi-st" id="yiyi-403"><em>timeout</em>是对<a class="reference internal" href="#threading.Barrier.wait" title="threading.Barrier.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>方法未指定的默认超时值。</span></p><dl class="method"><dt id="threading.Barrier.wait"><span class="yiyi-st" id="yiyi-404"> <code class="descname">wait</code><span class="sig-paren">(</span><em>timeout=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-405">通过障碍。</span><span class="yiyi-st" id="yiyi-406">当所有线程方面的屏障都调用了这个函数,它们都被同时释放。</span><span class="yiyi-st" id="yiyi-407">如果提供了<em>超时</em>,它优先于提供给类构造函数的任何内容。</span></p><p><span class="yiyi-st" id="yiyi-408">返回值是范围为0至<em>各方</em> - 1的整数每个线程不同。</span><span class="yiyi-st" id="yiyi-409">这可以用于选择线程做一些特殊的内务处理,例如。</span><span class="yiyi-st" id="yiyi-410"></span></p><pre><code class="language-python"><span></span><span class="n">i</span> <span class="o">=</span> <span class="n">barrier</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="c1"># Only one thread needs to print this</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"passed the barrier"</span><span class="p">)</span>
</code></pre><p><span class="yiyi-st" id="yiyi-411">如果向构造函数提供<em>操作</em>,则其中一个线程将在释放之前调用它。</span><span class="yiyi-st" id="yiyi-412">如果这个调用引发一个错误,那么屏障就进入破坏状态。</span></p><p><span class="yiyi-st" id="yiyi-413">如果呼叫超时,屏障被置于断开状态。</span></p><p><span class="yiyi-st" id="yiyi-414">如果在线程等待时障碍被破坏或重置,此方法可能引发<a class="reference internal" href="#threading.BrokenBarrierError" title="threading.BrokenBarrierError"><code class="xref py py-class docutils literal"><span class="pre">BrokenBarrierError</span></code></a>异常。</span></p></dd></dl><dl class="method"><dt id="threading.Barrier.reset"><span class="yiyi-st" id="yiyi-415"> <code class="descname">reset</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-416">将屏障返回到默认空状态。</span><span class="yiyi-st" id="yiyi-417">任何等待的线程都会收到<a class="reference internal" href="#threading.BrokenBarrierError" title="threading.BrokenBarrierError"><code class="xref py py-class docutils literal"><span class="pre">BrokenBarrierError</span></code></a>异常。</span></p><p><span class="yiyi-st" id="yiyi-418">注意,如果有其他线程的状态未知,使用此函数可能需要一些外部同步。</span><span class="yiyi-st" id="yiyi-419">如果一个障碍被打破,最好只是离开它并创造一个新的。</span></p></dd></dl><dl class="method"><dt id="threading.Barrier.abort"><span class="yiyi-st" id="yiyi-420"> <code class="descname">abort</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-421">将障碍物置于破碎状态。</span><span class="yiyi-st" id="yiyi-422">这会导致对<a class="reference internal" href="#threading.Barrier.wait" title="threading.Barrier.wait"><code class="xref py py-meth docutils literal"><span class="pre">wait()</span></code></a>的任何活动或未来调用失败,并返回<a class="reference internal" href="#threading.BrokenBarrierError" title="threading.BrokenBarrierError"><code class="xref py py-class docutils literal"><span class="pre">BrokenBarrierError</span></code></a></span><span class="yiyi-st" id="yiyi-423">使用这个例如如果一个需要中止,以避免死锁应用程序。</span></p><p><span class="yiyi-st" id="yiyi-424">可能优选的是简单地创建具有敏感的<em>超时</em>值的障碍以自动防止线程中的一个线程变坏。</span></p></dd></dl><dl class="attribute"><dt id="threading.Barrier.parties"><span class="yiyi-st" id="yiyi-425"> <code class="descname">parties</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-426">通过屏障所需的螺纹数。</span></p></dd></dl><dl class="attribute"><dt id="threading.Barrier.n_waiting"><span class="yiyi-st" id="yiyi-427"> <code class="descname">n_waiting</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-428">当前在屏障中等待的线程数。</span></p></dd></dl><dl class="attribute"><dt id="threading.Barrier.broken"><span class="yiyi-st" id="yiyi-429"> <code class="descname">broken</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-430">如果障碍处于中断状态,则为<code class="docutils literal"><span class="pre">True</span></code>的布尔值。</span></p></dd></dl></dd></dl><dl class="exception"><dt id="threading.BrokenBarrierError"><span class="yiyi-st" id="yiyi-431"> <em class="property">exception </em><code class="descclassname">threading.</code><code class="descname">BrokenBarrierError</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-432"><a class="reference internal" href="#threading.Barrier" title="threading.Barrier"><code class="xref py py-class docutils literal"><span class="pre">Barrier</span></code></a>对象重置或断开时,会引发此异常(<a class="reference internal" href="exceptions.html#RuntimeError" title="RuntimeError"><code class="xref py py-exc docutils literal"><span class="pre">RuntimeError</span></code></a>的子类)。</span></p></dd></dl></div><div class="section" id="using-locks-conditions-and-semaphores-in-the-with-statement"><h2><span class="yiyi-st" id="yiyi-433">17.1.10. </span><span class="yiyi-st" id="yiyi-434"><a class="reference internal" href="../reference/compound_stmts.html#with"><code class="xref std std-keyword docutils literal"><span class="pre">with</span></code></a>语句中使用锁、条件和信号量</span></h2><p><span class="yiyi-st" id="yiyi-435">本模块提供的所有具有<code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code><code class="xref py py-meth docutils literal"><span class="pre">release()</span></code>方法的对象,可以用作<a class="reference internal" href="../reference/compound_stmts.html#with"><code class="xref std std-keyword docutils literal"><span class="pre">with</span></code></a>语句的上下文管理器。</span><span class="yiyi-st" id="yiyi-436">当输入块时,将调用<code class="xref py py-meth docutils literal"><span class="pre">acquire()</span></code>方法,当退出块时将调用<code class="xref py py-meth docutils literal"><span class="pre">release()</span></code></span><span class="yiyi-st" id="yiyi-437">因此,以下片段:</span></p><pre><code class="language-python"><span></span><span class="k">with</span> <span class="n">some_lock</span><span class="p">:</span>
<span class="c1"># do something...</span>
</code></pre><p><span class="yiyi-st" id="yiyi-438">等效于:</span></p><pre><code class="language-python"><span></span><span class="n">some_lock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># do something...</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">some_lock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
</code></pre><p><span class="yiyi-st" id="yiyi-439">目前,<a class="reference internal" href="#threading.Lock" title="threading.Lock"><code class="xref py py-class docutils literal"><span class="pre">Lock</span></code></a><a class="reference internal" href="#threading.RLock" title="threading.RLock"><code class="xref py py-class docutils literal"><span class="pre">RLock</span></code></a><a class="reference internal" href="#threading.Condition" title="threading.Condition"><code class="xref py py-class docutils literal"><span class="pre">Condition</span></code></a><a class="reference internal" href="#threading.Semaphore" title="threading.Semaphore"><code class="xref py py-class docutils literal"><span class="pre">Semaphore</span></code></a><a class="reference internal" href="#threading.BoundedSemaphore" title="threading.BoundedSemaphore"><code class="xref py py-class docutils literal"><span class="pre">BoundedSemaphore</span></code></a>用作<a class="reference internal" href="../reference/compound_stmts.html#with"><code class="xref std std-keyword docutils literal"><span class="pre">with</span></code></a>语句上下文管理器。</span></p></div></div></div>