11.. _a-conceptual-overview-of-asyncio :
22
3- *************************************** 
4- A Conceptual Overview of :mod: `asyncio `
5- *************************************** 
3+ ****************************************  
4+ A Conceptual Overview of :mod: `! asyncio
5+ ****************************************  
66
7- This article seeks to help you build a sturdy mental model of how `` asyncio ` `
7+ This article seeks to help you build a sturdy mental model of how :mod: ` asyncio `
88fundamentally works, helping you understand the how and why behind the
99recommended patterns.
1010
11- You might be curious about some key `` asyncio ` ` concepts.
11+ You might be curious about some key :mod: ` ! asyncio
1212You'll be comfortably able to answer these questions by the end of this
1313article.
1414
1515- What's happening behind the scenes when an object is ``await ``\  ed?
16- - How does `` asyncio ``  differentiate between a task which doesn't need CPU-time 
17-   (such as a network request or file read) as opposed to a task that does 
18-   (such as computing n-factorial)?
16+ - How does :mod: ` ! asyncio
17+   CPU-time  (such as a network request or file read) as opposed to a task that
18+   does  (such as computing n-factorial)?
1919- How would I go about writing my own asynchronous variant of some operation?
2020  Something like an async sleep, database request, and so on.
2121
@@ -28,14 +28,14 @@ article.
2828A conceptual overview part 1: the high-level
2929-------------------------------------------- 
3030
31- In part 1, we'll cover the main, high-level building blocks of `` asyncio ` `:
31+ In part 1, we'll cover the main, high-level building blocks of :mod: ` ! asyncio
3232the event loop, coroutine functions, coroutine objects, tasks and ``await ``.
3333
3434========== 
3535Event Loop
3636========== 
3737
38- Everything in `` asyncio ` ` happens relative to the event loop.
38+ Everything in :mod: ` ! asyncio
3939It's the star of the show.
4040It's like an orchestra conductor.
4141It's behind the scenes managing resources.
@@ -44,7 +44,7 @@ done comes from the respect and cooperation of its teammates.
4444
4545In more technical terms, the event loop contains a queue of jobs (or "chunks
4646of work") to be run.
47- Some jobs are added directly by you, and some indirectly by `` asyncio ` `.
47+ Some jobs are added directly by you, and some indirectly by :mod: ` ! asyncio
4848The event loop pops a job from the queue and invokes it (or "gives it control"),
4949similar to calling a function, then that job runs.
5050Once it pauses or completes, it returns control to the event loop.
@@ -107,8 +107,9 @@ as coroutine.
107107That can be confusing!
108108In this article, coroutine specifically refers to a coroutine object, or more
109109precisely, an instance of :data: `types.CoroutineType ` (native coroutine).
110- Note that coroutines can also exist as instances of :class: `collections.abc.Coroutine `
111- -- a distinction that matters for type checking.
110+ Note that coroutines can also exist as instances of
111+ :class: `collections.abc.Coroutine ` -- a distinction that matters for type
112+ checking.
112113
113114A coroutine represents the function's body or logic.
114115A coroutine has to be explicitly started; again, merely creating the coroutine
@@ -120,7 +121,8 @@ That pausing and resuming ability is what allows for asynchronous behavior!
120121Coroutines and coroutine functions were built by leveraging the functionality
121122of :term: `generators <generator iterator> ` and
122123:term: `generator functions <generator> `.
123- Recall, a generator function is a function that :keyword: `yield `\s , like this one::
124+ Recall, a generator function is a function that :keyword: `yield `\s , like this
125+ one::
124126
125127   def get_random_number(): 
126128       # This would be a bad random number generator! 
@@ -162,7 +164,7 @@ clear in a moment when we discuss ``await``.
162164The recommended way to create tasks is via :func: `asyncio.create_task `.
163165Creating a task automatically adds it to the event loop's queue of tasks.
164166
165- Since there's only one event loop (in each thread), `` asyncio ` ` takes care of
167+ Since there's only one event loop (in each thread), :mod: ` ! asyncio
166168associating the task with the event loop for you. As such, there's no need
167169to specify the event loop.
168170
@@ -196,9 +198,10 @@ In practice, it's slightly more complex, but not by much.
196198In part 2, we'll walk through the details that make this possible.
197199
198200**Unlike tasks, awaiting a coroutine does not cede control! **
199- Wrapping a coroutine in a task first, then ``await ``\  ing that would cede control.
200- The behavior of ``await coroutine `` is effectively the same as invoking a regular,
201- synchronous Python function.
201+ Wrapping a coroutine in a task first, then ``await ``\  ing that would cede
202+ control.
203+ The behavior of ``await coroutine `` is effectively the same as invoking a
204+ regular, synchronous Python function.
202205Consider this program::
203206
204207   import asyncio 
@@ -248,7 +251,8 @@ The event loop then works through its queue, calling ``coro_b()`` and then
248251A conceptual overview part 2: the nuts and bolts
249252------------------------------------------------ 
250253
251- Part 2 goes into detail on the mechanisms ``asyncio `` uses to manage control flow.
254+ Part 2 goes into detail on the mechanisms :mod: `!asyncio ` uses to manage
255+ control flow.
252256This is where the magic happens.
253257You'll come away from this section knowing what await does behind the scenes
254258and how to make your own asynchronous operators.
@@ -257,16 +261,18 @@ and how to make your own asynchronous operators.
257261coroutine.send(), await, yield and StopIteration
258262================================================ 
259263
260- `` asyncio ` ` leverages 4 components to pass around control.
264+ :mod: ` ! asyncio
261265
262- :meth: `coroutine.send(arg) <generator.send> ` is the method used to start or resume a coroutine.
266+ :meth: `coroutine.send(arg) <generator.send> ` is the method used to start or
267+ resume a coroutine.
263268If the coroutine was paused and is now being resumed, the argument ``arg ``
264269will be sent in as the return value of the ``yield `` statement which originally
265270paused it.
266271If the coroutine is being started, as opposed to resumed, ``arg `` must be
267272``None ``.
268273
269- :ref: `yield  <yieldexpr >`, like usual, pauses execution and returns control to the caller.
274+ :ref: `yield  <yieldexpr >`, like usual, pauses execution and returns control
275+ to the caller.
270276In the example below, the ``yield ``, on line 3, is called by
271277``... = await rock `` on line 11.
272278Generally, ``await `` calls the :meth: `~object.__await__ ` method of the given
@@ -407,10 +413,11 @@ preventing other tasks from running.
407413       await asyncio.gather(*work_tasks) 
408414
409415
410- Below, we use a future to enable custom control over when that task will be marked
411- as done.
412- If :meth: `future.set_result() <asyncio.Future.set_result> ` (the method responsible for marking that future as
413- done) is never called, then this task will never finish.
416+ Below, we use a future to enable custom control over when that task will be
417+ marked as done.
418+ If :meth: `future.set_result() <asyncio.Future.set_result> ` (the method
419+ responsible for marking that future as done) is never called, then this task
420+ will never finish.
414421We've also enlisted the help of another task, which we'll see in a moment, that
415422will monitor how much time has elapsed and accordingly call
416423``future.set_result() ``.
@@ -435,8 +442,8 @@ As usual, the event loop cycles through its queue of tasks, giving them control
435442and receiving control back when they pause or finish.
436443The ``watcher_task ``, which runs the coroutine ``_sleep_watcher(...) ``, will
437444be invoked once per full cycle of the event loop's queue.
438- On each resumption, it'll check the time and if not enough has elapsed, then it'll 
439- pause once again and hand control back to the event loop.
445+ On each resumption, it'll check the time and if not enough has elapsed, then
446+ it'll  pause once again and hand control back to the event loop.
440447Eventually, enough time will have elapsed, and ``_sleep_watcher(...) `` will
441448mark the future as done, and then itself finish too by breaking out of the
442449infinite ``while `` loop.
0 commit comments