python-peps/pep-0319/index.html

602 lines
48 KiB
HTML
Raw Permalink 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.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 319 Python Synchronize/Asynchronize Block | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0319/">
<link rel="stylesheet" href="../_static/style.css" type="text/css">
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
<meta property="og:title" content='PEP 319 Python Synchronize/Asynchronize Block | peps.python.org'>
<meta property="og:description" content="This PEP proposes adding two new keywords to Python, synchronize and asynchronize.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0319/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="This PEP proposes adding two new keywords to Python, synchronize and asynchronize.">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 319</li>
</ul>
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
</button>
</header>
<article>
<section id="pep-content">
<h1 class="page-title">PEP 319 Python Synchronize/Asynchronize Block</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Michel Pelletier &lt;michel&#32;&#97;t&#32;users.sourceforge.net&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">24-Feb-2003</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.4</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#pronouncement">Pronouncement</a></li>
<li><a class="reference internal" href="#synchronization-targets">Synchronization Targets</a></li>
<li><a class="reference internal" href="#other-patterns-that-synchronize">Other Patterns that Synchronize</a></li>
<li><a class="reference internal" href="#formal-syntax">Formal Syntax</a></li>
<li><a class="reference internal" href="#proposed-implementation">Proposed Implementation</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#pep-310-reliable-acquisition-release-pairs">PEP 310 Reliable Acquisition/Release Pairs</a></li>
<li><a class="reference internal" href="#how-java-does-it">How Java Does It</a></li>
<li><a class="reference internal" href="#how-jython-does-it">How Jython Does It</a></li>
<li><a class="reference internal" href="#summary-of-proposed-changes-to-python">Summary of Proposed Changes to Python</a></li>
<li><a class="reference internal" href="#risks">Risks</a></li>
<li><a class="reference internal" href="#dissenting-opinion">Dissenting Opinion</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP proposes adding two new keywords to Python, synchronize
and asynchronize.</p>
</section>
<section id="pronouncement">
<h2><a class="toc-backref" href="#pronouncement" role="doc-backlink">Pronouncement</a></h2>
<p>This PEP is rejected in favor of <a class="pep reference internal" href="../pep-0343/" title="PEP 343 The “with” Statement">PEP 343</a>.</p>
<dl>
<dt>The synchronize Keyword</dt><dd>The concept of code synchronization in Python is too low-level.
To synchronize code a programmer must be aware of the details of
the following pseudo-code pattern:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">initialize_lock</span><span class="p">()</span>
<span class="o">...</span>
<span class="n">acquire_lock</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">release_lock</span><span class="p">()</span>
</pre></div>
</div>
<p>This synchronized block pattern is not the only pattern (more
discussed below) but it is very common. This PEP proposes
replacing the above code with the following equivalent:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">synchronize</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
</pre></div>
</div>
<p>The advantages of this scheme are simpler syntax and less room for
user error. Currently users are required to write code about
acquiring and releasing thread locks in try/finally blocks;
errors in this code can cause notoriously difficult concurrent
thread locking issues.</p>
</dd>
<dt>The asynchronize Keyword</dt><dd>While executing a synchronize block of code a programmer may
want to “drop back” to running asynchronously momentarily to run
blocking input/output routines or something else that might take an
indeterminate amount of time and does not require synchronization.
This code usually follows the pattern:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">initialize_lock</span><span class="p">()</span>
<span class="o">...</span>
<span class="n">acquire_lock</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
<span class="n">release_lock</span><span class="p">()</span> <span class="c1"># become async</span>
<span class="n">do_blocking_io</span><span class="p">()</span>
<span class="n">acquire_lock</span><span class="p">()</span> <span class="c1"># sync again</span>
<span class="n">change_shared_data2</span><span class="p">()</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">release_lock</span><span class="p">()</span>
</pre></div>
</div>
<p>The asynchronous section of the code is not very obvious visually,
so it is marked up with comments. Using the proposed
asynchronize keyword this code becomes much cleaner, easier to
understand, and less prone to error:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">synchronize</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
<span class="n">asynchronize</span><span class="p">:</span>
<span class="n">do_blocking_io</span><span class="p">()</span>
<span class="n">change_shared_data2</span><span class="p">()</span>
</pre></div>
</div>
<p>Encountering an asynchronize keyword inside a non-synchronized
block can raise either an error or issue a warning (as all code
blocks are implicitly asynchronous anyway). It is important to
note that the above example is <strong>not</strong> the same as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">synchronize</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
<span class="n">do_blocking_io</span><span class="p">()</span>
<span class="n">synchronize</span><span class="p">:</span>
<span class="n">change_shared_data2</span><span class="p">()</span>
</pre></div>
</div>
<p>Because both synchronized blocks of code may be running inside the
same iteration of a loop, Consider:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">while</span> <span class="n">in_main_loop</span><span class="p">():</span>
<span class="n">synchronize</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
<span class="n">asynchronize</span><span class="p">:</span>
<span class="n">do_blocking_io</span><span class="p">()</span>
<span class="n">change_shared_data2</span><span class="p">()</span>
</pre></div>
</div>
<p>Many threads may be looping through this code. Without the
asynchronize keyword one thread cannot stay in the loop and
release the lock at the same time while blocking IO is going on.
This pattern of releasing locks inside a main loop to do blocking
IO is used extensively inside the CPython interpreter itself.</p>
</dd>
</dl>
</section>
<section id="synchronization-targets">
<h2><a class="toc-backref" href="#synchronization-targets" role="doc-backlink">Synchronization Targets</a></h2>
<p>As proposed the synchronize and asynchronize keywords
synchronize a block of code. However programmers may want to
specify a target object that threads synchronize on. Any object
can be a synchronization target.</p>
<p>Consider a two-way queue object: two different objects are used by
the same synchronize code block to synchronize both queues
separately in the get method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">TwoWayQueue</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">front</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rear</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span><span class="w"> </span><span class="nf">putFront</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">front</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">getFront</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">item</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">front</span><span class="p">)</span>
<span class="k">return</span> <span class="n">item</span>
<span class="k">def</span><span class="w"> </span><span class="nf">putRear</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rear</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">getRear</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">item</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rear</span><span class="p">)</span>
<span class="k">return</span> <span class="n">item</span>
<span class="k">def</span><span class="w"> </span><span class="nf">put</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">queue</span><span class="p">):</span>
<span class="n">synchronize</span> <span class="n">queue</span><span class="p">:</span>
<span class="n">queue</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">queue</span><span class="p">):</span>
<span class="n">synchronize</span> <span class="n">queue</span><span class="p">:</span>
<span class="n">item</span> <span class="o">=</span> <span class="n">queue</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">del</span> <span class="n">queue</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">item</span>
</pre></div>
</div>
<p>Here is the equivalent code in Python as it is now without a
synchronize keyword:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">thread</span>
<span class="k">class</span><span class="w"> </span><span class="nc">LockableQueue</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">queue</span> <span class="o">=</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">thread</span><span class="o">.</span><span class="n">allocate_lock</span><span class="p">()</span>
<span class="k">class</span><span class="w"> </span><span class="nc">TwoWayQueue</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">front</span> <span class="o">=</span> <span class="n">LockableQueue</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">rear</span> <span class="o">=</span> <span class="n">LockableQueue</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">putFront</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">front</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">getFront</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">item</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">front</span><span class="p">)</span>
<span class="k">return</span> <span class="n">item</span>
<span class="k">def</span><span class="w"> </span><span class="nf">putRear</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rear</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">getRear</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">item</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rear</span><span class="p">)</span>
<span class="k">return</span> <span class="n">item</span>
<span class="k">def</span><span class="w"> </span><span class="nf">put</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="n">queue</span><span class="p">):</span>
<span class="n">queue</span><span class="o">.</span><span class="n">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="n">queue</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">queue</span><span class="o">.</span><span class="n">lock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">queue</span><span class="p">):</span>
<span class="n">queue</span><span class="o">.</span><span class="n">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="n">item</span> <span class="o">=</span> <span class="n">queue</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">del</span> <span class="n">queue</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">item</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">queue</span><span class="o">.</span><span class="n">lock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
</pre></div>
</div>
<p>The last example had to define an extra class to associate a lock
with the queue where the first example the synchronize keyword
does this association internally and transparently.</p>
</section>
<section id="other-patterns-that-synchronize">
<h2><a class="toc-backref" href="#other-patterns-that-synchronize" role="doc-backlink">Other Patterns that Synchronize</a></h2>
<p>There are some situations where the synchronize and
asynchronize keywords cannot entirely replace the use of lock
methods like <code class="docutils literal notranslate"><span class="pre">acquire</span></code> and <code class="docutils literal notranslate"><span class="pre">release</span></code>. Some examples are if the
programmer wants to provide arguments for <code class="docutils literal notranslate"><span class="pre">acquire</span></code> or if a lock
is acquired in one code block but released in another, as shown
below.</p>
<p>Here is a class from Zope modified to use both the synchronize
and asynchronize keywords and also uses a pool of explicit locks
that are acquired and released in different code blocks and thus
dont use synchronize:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">thread</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">ZServerPublisher</span><span class="w"> </span><span class="kn">import</span> <span class="n">ZServerPublisher</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ZRendevous</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="n">pool</span><span class="o">=</span><span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_lists</span><span class="o">=</span><span class="n">pool</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="n">synchronize</span><span class="p">:</span>
<span class="k">while</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">l</span><span class="o">=</span><span class="n">thread</span><span class="o">.</span><span class="n">allocate_lock</span><span class="p">()</span>
<span class="n">l</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="n">pool</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="n">thread</span><span class="o">.</span><span class="n">start_new_thread</span><span class="p">(</span><span class="n">ZServerPublisher</span><span class="p">,</span>
<span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">accept</span><span class="p">,))</span>
<span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span>
<span class="k">def</span><span class="w"> </span><span class="nf">accept</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">synchronize</span><span class="p">:</span>
<span class="n">pool</span><span class="p">,</span> <span class="n">requests</span><span class="p">,</span> <span class="n">ready</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_lists</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">requests</span><span class="p">:</span>
<span class="n">l</span><span class="o">=</span><span class="n">pool</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">del</span> <span class="n">pool</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">ready</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="n">asynchronize</span><span class="p">:</span>
<span class="n">l</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="n">pool</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="n">r</span><span class="o">=</span><span class="n">requests</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">del</span> <span class="n">requests</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">r</span>
<span class="k">def</span><span class="w"> </span><span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="n">synchronize</span><span class="p">:</span>
<span class="n">pool</span><span class="p">,</span> <span class="n">requests</span><span class="p">,</span> <span class="n">ready</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_lists</span>
<span class="n">requests</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">name</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">))</span>
<span class="k">if</span> <span class="n">ready</span><span class="p">:</span>
<span class="n">l</span><span class="o">=</span><span class="n">ready</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">del</span> <span class="n">ready</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">l</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
</pre></div>
</div>
<p>Here is the original class as found in the
Zope/ZServer/PubCore/ZRendevous.py module. The “convenience” of
the _a and _r shortcut names obscure the code:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">thread</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">ZServerPublisher</span><span class="w"> </span><span class="kn">import</span> <span class="n">ZServerPublisher</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ZRendevous</span><span class="p">:</span>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="n">sync</span><span class="o">=</span><span class="n">thread</span><span class="o">.</span><span class="n">allocate_lock</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_a</span><span class="o">=</span><span class="n">sync</span><span class="o">.</span><span class="n">acquire</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_r</span><span class="o">=</span><span class="n">sync</span><span class="o">.</span><span class="n">release</span>
<span class="n">pool</span><span class="o">=</span><span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_lists</span><span class="o">=</span><span class="n">pool</span><span class="p">,</span> <span class="p">[],</span> <span class="p">[]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_a</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">while</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">l</span><span class="o">=</span><span class="n">thread</span><span class="o">.</span><span class="n">allocate_lock</span><span class="p">()</span>
<span class="n">l</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="n">pool</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="n">thread</span><span class="o">.</span><span class="n">start_new_thread</span><span class="p">(</span><span class="n">ZServerPublisher</span><span class="p">,</span>
<span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">accept</span><span class="p">,))</span>
<span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span>
<span class="k">finally</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_r</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">accept</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_a</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">pool</span><span class="p">,</span> <span class="n">requests</span><span class="p">,</span> <span class="n">ready</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_lists</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">requests</span><span class="p">:</span>
<span class="n">l</span><span class="o">=</span><span class="n">pool</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">del</span> <span class="n">pool</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">ready</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_r</span><span class="p">()</span>
<span class="n">l</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_a</span><span class="p">()</span>
<span class="n">pool</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
<span class="n">r</span><span class="o">=</span><span class="n">requests</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">del</span> <span class="n">requests</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">r</span>
<span class="k">finally</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_r</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_a</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">pool</span><span class="p">,</span> <span class="n">requests</span><span class="p">,</span> <span class="n">ready</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_lists</span>
<span class="n">requests</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">name</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">response</span><span class="p">))</span>
<span class="k">if</span> <span class="n">ready</span><span class="p">:</span>
<span class="n">l</span><span class="o">=</span><span class="n">ready</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="k">del</span> <span class="n">ready</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">l</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
<span class="k">finally</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_r</span><span class="p">()</span>
</pre></div>
</div>
<p>In particular the asynchronize section of the <code class="docutils literal notranslate"><span class="pre">accept</span></code> method is
not very obvious. To beginner programmers, synchronize and
asynchronize remove many of the problems encountered when
juggling multiple <code class="docutils literal notranslate"><span class="pre">acquire</span></code> and <code class="docutils literal notranslate"><span class="pre">release</span></code> methods on different
locks in different <code class="docutils literal notranslate"><span class="pre">try/finally</span></code> blocks.</p>
</section>
<section id="formal-syntax">
<h2><a class="toc-backref" href="#formal-syntax" role="doc-backlink">Formal Syntax</a></h2>
<p>Python syntax is defined in a modified BNF grammar notation
described in the Python Language Reference <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a>. This section
describes the proposed synchronization syntax using this grammar:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">synchronize_stmt</span><span class="p">:</span> <span class="s1">&#39;synchronize&#39;</span> <span class="p">[</span><span class="n">test</span><span class="p">]</span> <span class="s1">&#39;:&#39;</span> <span class="n">suite</span>
<span class="n">asynchronize_stmt</span><span class="p">:</span> <span class="s1">&#39;asynchronize&#39;</span> <span class="p">[</span><span class="n">test</span><span class="p">]</span> <span class="s1">&#39;:&#39;</span> <span class="n">suite</span>
<span class="n">compound_stmt</span><span class="p">:</span> <span class="o">...</span> <span class="o">|</span> <span class="n">synchronized_stmt</span> <span class="o">|</span> <span class="n">asynchronize_stmt</span>
</pre></div>
</div>
<p>(The ‘…’ indicates other compound statements elided).</p>
</section>
<section id="proposed-implementation">
<h2><a class="toc-backref" href="#proposed-implementation" role="doc-backlink">Proposed Implementation</a></h2>
<p>The author of this PEP has not explored an implementation yet.
There are several implementation issues that must be resolved.
The main implementation issue is what exactly gets locked and
unlocked during a synchronized block.</p>
<p>During an unqualified synchronized block (the use of the
synchronize keyword without a target argument) a lock could be
created and associated with the synchronized code block object.
Any threads that are to execute the block must first acquire the
code block lock.</p>
<p>When an asynchronize keyword is encountered in a synchronize
block the code block lock is unlocked before the inner block is
executed and re-locked when the inner block terminates.</p>
<p>When a synchronized block target is specified the object is
associated with a lock. How this is implemented cleanly is
probably the highest risk of this proposal. Java Virtual Machines
typically associate a special hidden lock object with target
object and use it to synchronized the block around the target
only.</p>
</section>
<section id="backward-compatibility">
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward Compatibility</a></h2>
<p>Backward compatibility is solved with the new <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span></code>
Python syntax (<a class="pep reference internal" href="../pep-0236/" title="PEP 236 Back to the __future__">PEP 236</a>), and the new warning framework (<a class="pep reference internal" href="../pep-0230/" title="PEP 230 Warning Framework">PEP 230</a>)
to evolve the
Python language into phasing out any conflicting names that use
the new keywords synchronize and asynchronize. To use the
syntax now, a developer could use the statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">__future__</span><span class="w"> </span><span class="kn">import</span> <span class="n">threadsync</span> <span class="c1"># or whatever</span>
</pre></div>
</div>
<p>In addition, any code that uses the keyword synchronize or
asynchronize as an identifier will be issued a warning from
Python. After the appropriate period of time, the syntax would
become standard, the above import statement would do nothing, and
any identifiers named synchronize or asynchronize would raise
an exception.</p>
</section>
<section id="pep-310-reliable-acquisition-release-pairs">
<h2><a class="toc-backref" href="#pep-310-reliable-acquisition-release-pairs" role="doc-backlink">PEP 310 Reliable Acquisition/Release Pairs</a></h2>
<p><a class="pep reference internal" href="../pep-0310/" title="PEP 310 Reliable Acquisition/Release Pairs">PEP 310</a> proposes the with keyword that can serve the same
function as synchronize (but no facility for asynchronize).
The pattern:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">initialize_lock</span><span class="p">()</span>
<span class="k">with</span> <span class="n">the_lock</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
</pre></div>
</div>
<p>is equivalent to the proposed:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">synchronize</span> <span class="n">the_lock</span><span class="p">:</span>
<span class="n">change_shared_data</span><span class="p">()</span>
</pre></div>
</div>
<p><a class="pep reference internal" href="../pep-0310/" title="PEP 310 Reliable Acquisition/Release Pairs">PEP 310</a> must synchronize on an existing lock, while this PEP
proposes that unqualified synchronize statements synchronize on
a global, internal, transparent lock in addition to qualified
synchronize statements. The with statement also requires lock
initialization, while the synchronize statement can synchronize
on any target object <strong>including</strong> locks.</p>
<p>While limited in this fashion, the with statement is more
abstract and serves more purposes than synchronization. For
example, transactions could be used with the with keyword:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">initialize_transaction</span><span class="p">()</span>
<span class="k">with</span> <span class="n">my_transaction</span><span class="p">:</span>
<span class="n">do_in_transaction</span><span class="p">()</span>
<span class="c1"># when the block terminates, the transaction is committed.</span>
</pre></div>
</div>
<p>The synchronize and asynchronize keywords cannot serve this or
any other general acquire/release pattern other than thread
synchronization.</p>
</section>
<section id="how-java-does-it">
<h2><a class="toc-backref" href="#how-java-does-it" role="doc-backlink">How Java Does It</a></h2>
<p>Java defines a synchronized keyword (note the grammatical tense
different between the Java keyword and this PEPs synchronize)
which must be qualified on any object. The syntax is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">synchronized</span> <span class="p">(</span><span class="n">Expression</span><span class="p">)</span> <span class="n">Block</span>
</pre></div>
</div>
<p>Expression must yield a valid object (null raises an error and
exceptions during Expression terminate the synchronized block
for the same reason) upon which Block is synchronized.</p>
</section>
<section id="how-jython-does-it">
<h2><a class="toc-backref" href="#how-jython-does-it" role="doc-backlink">How Jython Does It</a></h2>
<p>Jython uses a synchronize class with the static method
make_synchronized that accepts one callable argument and returns
a newly created, synchronized, callable “wrapper” around the
argument.</p>
</section>
<section id="summary-of-proposed-changes-to-python">
<h2><a class="toc-backref" href="#summary-of-proposed-changes-to-python" role="doc-backlink">Summary of Proposed Changes to Python</a></h2>
<p>Adding new synchronize and asynchronize keywords to the
language.</p>
</section>
<section id="risks">
<h2><a class="toc-backref" href="#risks" role="doc-backlink">Risks</a></h2>
<p>This PEP proposes adding two keywords to the Python language. This
may break code.</p>
<p>There is no implementation to test.</p>
<p>Its not the most important problem facing Python programmers
today (although it is a fairly notorious one).</p>
<p>The equivalent Java keyword is the past participle synchronized.
This PEP proposes the present tense, synchronize as being more
in spirit with Python (there being less distinction between
compile-time and run-time in Python than Java).</p>
</section>
<section id="dissenting-opinion">
<h2><a class="toc-backref" href="#dissenting-opinion" role="doc-backlink">Dissenting Opinion</a></h2>
<p>This PEP has not been discussed on python-dev.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id2" role="doc-footnote">
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
<dd>The Python Language Reference
<a class="reference external" href="http://docs.python.org/reference/">http://docs.python.org/reference/</a></aside>
</aside>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0319.rst">https://github.com/python/peps/blob/main/peps/pep-0319.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0319.rst">2025-02-01 08:59:27 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#pronouncement">Pronouncement</a></li>
<li><a class="reference internal" href="#synchronization-targets">Synchronization Targets</a></li>
<li><a class="reference internal" href="#other-patterns-that-synchronize">Other Patterns that Synchronize</a></li>
<li><a class="reference internal" href="#formal-syntax">Formal Syntax</a></li>
<li><a class="reference internal" href="#proposed-implementation">Proposed Implementation</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#pep-310-reliable-acquisition-release-pairs">PEP 310 Reliable Acquisition/Release Pairs</a></li>
<li><a class="reference internal" href="#how-java-does-it">How Java Does It</a></li>
<li><a class="reference internal" href="#how-jython-does-it">How Jython Does It</a></li>
<li><a class="reference internal" href="#summary-of-proposed-changes-to-python">Summary of Proposed Changes to Python</a></li>
<li><a class="reference internal" href="#risks">Risks</a></li>
<li><a class="reference internal" href="#dissenting-opinion">Dissenting Opinion</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0319.rst">Page Source (GitHub)</a>
</nav>
</section>
<script src="../_static/colour_scheme.js"></script>
<script src="../_static/wrap_tables.js"></script>
<script src="../_static/sticky_banner.js"></script>
</body>
</html>