Skip to content

Commit e3fb944

Browse files
Add the concurrency howto doc.
1 parent 4187872 commit e3fb944

File tree

3 files changed

+510
-0
lines changed

3 files changed

+510
-0
lines changed

Doc/howto/concurrency.rst

Lines changed: 330 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
.. _concurrency-howto:
2+
3+
*****************
4+
Concurrency HOWTO
5+
*****************
6+
7+
Python is a language the accommodates a variety of programming styles,
8+
from procedural to object-oriented to functional. The same applies
9+
to concurrency. Here we'll look at how different concurrency models
10+
look in Python, with an emphasis on practical workload-oriented examples.
11+
12+
The following Python concurrency models are covered:
13+
14+
* threads (:mod:`threading` and :mod:`concurrent.futures`)
15+
* multi-processing (:mod:`multiprocessing` and :mod:`concurrent.futures`)
16+
* async/await
17+
* CSP/actor model (:mod:`!interpreters`)
18+
* distributed (e.g. SMP)
19+
20+
Each of these will be explained, with some simple examples. The later
21+
workload-oriented examples will be implemented using each,
22+
for comparison, when possible.
23+
24+
.. note::
25+
26+
You should always make sure concurrency is the right tool for the job
27+
before you reach for it when solving your problem. There are many
28+
cases where concurrency simply isn't applicable or will only
29+
complicate the solution. In-depth discussion of this point
30+
is outside the scope of this document.
31+
32+
33+
All About Concurrency
34+
=====================
35+
36+
What is concurrency?
37+
--------------------
38+
39+
At its most fundamental, concurrency means doing multiple things at once,
40+
from a strictly *logical* viewpoint.
41+
42+
When a computer program runs, it executes a sequence of code in order.
43+
Sometimes it makes sense to break up that sequence into smaller pieces,
44+
where some of them can run independently of others.
45+
46+
For example, consider the following program with three pieces::
47+
48+
prep
49+
do A
50+
do B
51+
52+
If both ``do A`` and ``do B`` only rely on ``prep`` having completed,
53+
then we could rearrange the program in one of the following ways and
54+
end up with the same result::
55+
56+
prep = prep prep = prep -----
57+
do B = do A do B = | |
58+
do A = = do A do B
59+
60+
In the first alternative, we swap ``do A`` and ``do B``. In the second
61+
one we split the original program into two programs that we can run at
62+
the same time. In the third one, we run ``do A`` and ``do B`` at the
63+
same time. "At the same time" means concurrency.
64+
65+
Concurrency often involves some degree of synchronization between
66+
the tasks. At the most basic conceptual level: one task may wait
67+
for another to finish.
68+
69+
In addition to code running at the same time, concurrency typically
70+
also involves some amount of resources shared between the concurrent
71+
tasks. That may include memory, files, and sockets.
72+
73+
What is parallelism?
74+
--------------------
75+
76+
Concurrency may happen in one of two ways. The concurrent tasks may
77+
share a single CPU, each running a little bit at a time, with the
78+
operating system (or language runtime) taking care of the switching.
79+
The other way is where each task runs on its own CPU, meaning they
80+
are physically running at the same time, not just logically.
81+
82+
That second way is parallelism.
83+
84+
What problems can concurrency help solve?
85+
-----------------------------------------
86+
87+
Primarily, concurrency can be helpful by making your program faster
88+
and more responsive (less latency), when possible. In other words,
89+
you get better computational throughput. That happens by enabling
90+
the following:
91+
92+
* run on multiple CPU cores (parallelism)
93+
* keep blocking resources from blocking the whole program
94+
* make sure critical tasks have priority
95+
* process results as they come, instead of waiting for them all
96+
97+
Other possible benefits:
98+
99+
* asynchronous events can be handled more cleanly
100+
* better efficiency using hardware resources
101+
* improved scalability
102+
103+
What are the downsides?
104+
-----------------------
105+
106+
The main challenge when using concurrency is the extra complexity.
107+
108+
.. XXX
109+
110+
* races on shared resources
111+
* error handling
112+
* ...
113+
114+
The operating system, along with some libraries and frameworks,
115+
can help mitigate the extra complexity. So can the concurrency
116+
model you use, which we'll talk about a little later..
117+
118+
Workloads
119+
---------
120+
121+
We've looked at what you can do with concurrency from a high level.
122+
Now let's look at some concrete examples.
123+
124+
125+
...
126+
127+
128+
Concurrency Models
129+
------------------
130+
131+
The concept of concurrency has been a part of the study and practice
132+
of computer software since the 1950s and 1960s, with various innovations
133+
since then. The application of the different theoretical concurrency
134+
models can be categorized as follows:
135+
136+
* free threads - using multiple threads in the same process,
137+
with no isolation between them
138+
* isolated threads - threads with strict isolation between them
139+
(e.g. CSP and actor model)
140+
* multiprocessing - using multiple isolated processes
141+
* distributed - multiprocessing across multiple computers
142+
* async/await - using coroutines (AKA cooperative multitasking)
143+
144+
(There are certainly others, but these are the focus here.)
145+
146+
There are tradeoffs to each. Free-threading probably has the most
147+
notoriety and the most examples, but is also the most likely to cause
148+
you pain.
149+
Isolated threads have few of the downsides but are less familiar.
150+
Multiprocessing and distributed are less efficient at smaller scales.
151+
Async can be straightforward, but may cascade throughout a code base,
152+
doesn't necessarily give you parallelism.
153+
154+
155+
Python Concurrency Models
156+
=========================
157+
158+
We've looked at concurrency and concurrency models generally.
159+
Now let's see what they look like in Python.
160+
161+
Free-threading
162+
--------------
163+
164+
The stdlib :mod:`threading` module ...
165+
166+
...
167+
168+
Multi-processing
169+
----------------
170+
171+
...
172+
173+
Async/Await
174+
-----------
175+
176+
...
177+
178+
Isolated Threads (CSP/Actor Model)
179+
----------------------------------
180+
181+
...
182+
183+
Distributed
184+
-----------
185+
186+
...
187+
188+
189+
Python Concurrency Workloads
190+
============================
191+
192+
...
193+
194+
also see:
195+
196+
* https://github.com/faster-cpython/ideas/wiki/Tables:-Workloads
197+
* https://github.com/ericsnowcurrently/concurrency-benchmarks
198+
199+
200+
Workload 1
201+
----------
202+
203+
# ...
204+
205+
.. raw:: html
206+
207+
<style>
208+
table.workload-example th
209+
{
210+
vertical-align: top;
211+
}
212+
213+
table.workload-example td
214+
{
215+
vertical-align: top;
216+
}
217+
</style>
218+
219+
.. list-table::
220+
:header-rows: 1
221+
:class: borderless workload-example
222+
:align: left
223+
224+
* - threads
225+
- multiple interpreters
226+
- async/await
227+
- multiple processes
228+
- SMP
229+
* - .. raw:: html
230+
231+
<details>
232+
<summary>(expand)</summary>
233+
234+
.. literalinclude:: ../includes/concurrency.py
235+
:name: concurrency-workload-1-threads
236+
:start-after: [start-w1-threads]
237+
:end-before: [end-w1-threads]
238+
:dedent:
239+
:linenos:
240+
241+
.. raw:: html
242+
243+
</details>
244+
245+
- .. raw:: html
246+
247+
<details>
248+
<summary>(expand)</summary>
249+
250+
.. literalinclude:: ../includes/concurrency.py
251+
:name: concurrency-workload-1-subinterpreters
252+
:start-after: [start-w1-subinterpreters]
253+
:end-before: [end-w1-subinterpreters]
254+
:dedent:
255+
:linenos:
256+
257+
.. raw:: html
258+
259+
</details>
260+
261+
- .. raw:: html
262+
263+
<details>
264+
<summary>(expand)</summary>
265+
266+
.. literalinclude:: ../includes/concurrency.py
267+
:name: concurrency-workload-1-async
268+
:start-after: [start-w1-async]
269+
:end-before: [end-w1-async]
270+
:dedent:
271+
:linenos:
272+
273+
.. raw:: html
274+
275+
</details>
276+
277+
- .. raw:: html
278+
279+
<details>
280+
<summary>(expand)</summary>
281+
282+
.. literalinclude:: ../includes/concurrency.py
283+
:name: concurrency-workload-1-multiprocessing
284+
:start-after: [start-w1-multiprocessing]
285+
:end-before: [end-w1-multiprocessing]
286+
:dedent:
287+
:linenos:
288+
289+
.. raw:: html
290+
291+
</details>
292+
293+
- .. raw:: html
294+
295+
<details>
296+
<summary>(expand)</summary>
297+
298+
.. literalinclude:: ../includes/concurrency.py
299+
:name: concurrency-workload-1-smp
300+
:start-after: [start-w1-smp]
301+
:end-before: [end-w1-smp]
302+
:dedent:
303+
:linenos:
304+
305+
.. raw:: html
306+
307+
</details>
308+
309+
Using :mod:`concurrent.futures`:
310+
311+
.. raw:: html
312+
313+
<details>
314+
<summary>(expand)</summary>
315+
316+
.. literalinclude:: ../includes/concurrency.py
317+
:name: concurrency-workload-1-concurrent-futures-thread
318+
:start-after: [start-w1-concurrent-futures-thread]
319+
:end-before: [end-w1-concurrent-futures-thread]
320+
:dedent:
321+
:linenos:
322+
323+
.. raw:: html
324+
325+
</details>
326+
327+
Workload 2
328+
----------
329+
330+
...

Doc/howto/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Python Library Reference.
1111
:maxdepth: 1
1212
:hidden:
1313

14+
concurrency.rst
1415
cporting.rst
1516
curses.rst
1617
descriptor.rst
@@ -51,6 +52,7 @@ General:
5152

5253
Advanced development:
5354

55+
* :ref:`concurrency-howto`
5456
* :ref:`curses-howto`
5557
* :ref:`freethreading-extensions-howto`
5658
* :ref:`isolating-extensions-howto`

0 commit comments

Comments
 (0)