@@ -9,12 +9,11 @@ model of how :mod:`asyncio` fundamentally works, helping you understand the
99how and why behind the recommended patterns.
1010
1111You might be curious about some key :mod: `!asyncio ` concepts.
12- You'll be comfortably able to answer these questions by the end of this
13- article:
12+ By the end of this article, you'll be able to comfortably answer these questions:
1413
1514- What's happening behind the scenes when an object is awaited?
1615- How does :mod: `!asyncio ` differentiate between a task which doesn't need
17-   CPU- time (such as a network request or file read) as opposed to a task that
16+   CPU  time (such as a network request or file read) as opposed to a task that
1817  does (such as computing n-factorial)?
1918- How to write an asynchronous variant of an operation, such as
2019  an async sleep or database request.
@@ -35,7 +34,7 @@ A conceptual overview part 1: the high-level
3534-------------------------------------------- 
3635
3736In part 1, we'll cover the main, high-level building blocks of :mod: `!asyncio `:
38- the event loop, coroutine functions, coroutine objects, tasks and ``await ``.
37+ the event loop, coroutine functions, coroutine objects, tasks,  and ``await ``.
3938
4039========== 
4140Event Loop
@@ -56,7 +55,7 @@ Once it pauses or completes, it returns control to the event loop.
5655The event loop will then select another job from its pool and invoke it.
5756You can *roughly * think of the collection of jobs as a queue: jobs are added and
5857then processed one at a time, generally (but not always) in order.
59- This process repeats indefinitely with the event loop cycling endlessly
58+ This process repeats indefinitely,  with the event loop cycling endlessly
6059onwards.
6160If there are no more jobs pending execution, the event loop is smart enough to
6261rest and avoid needlessly wasting CPU cycles, and will come back when there's
@@ -276,7 +275,7 @@ in this case, a call to resume ``plant_a_tree()``.
276275
277276Generally speaking, when the awaited task finishes (``dig_the_hole_task ``),
278277the original task or coroutine (``plant_a_tree() ``) is added back to the event
279- loops  to-do list to be resumed.
278+ loop's  to-do list to be resumed.
280279
281280This is a basic, yet reliable mental model.
282281In practice, the control handoffs are slightly more complex, but not by much.
@@ -310,7 +309,7 @@ Consider this program::
310309The first statement in the coroutine ``main() `` creates ``task_b `` and schedules
311310it for execution via the event loop.
312311Then, ``coro_a() `` is repeatedly awaited. Control never cedes to the
313- event loop which is why we see the output of all three ``coro_a() ``
312+ event loop,  which is why we see the output of all three ``coro_a() ``
314313invocations before ``coro_b() ``'s output:
315314
316315.. code-block :: none 
@@ -338,8 +337,8 @@ This behavior of ``await coroutine`` can trip a lot of people up!
338337That example highlights how using only ``await coroutine `` could
339338unintentionally hog control from other tasks and effectively stall the event
340339loop.
341- :func: `asyncio.run ` can help you detect such occurences  via the
342- ``debug=True `` flag which accordingly  enables
340+ :func: `asyncio.run ` can help you detect such occurrences  via the
341+ ``debug=True `` flag,  which enables
343342:ref: `debug mode  <asyncio-debug-mode >`.
344343Among other things, it will log any coroutines that monopolize execution for
345344100ms or longer.
@@ -348,8 +347,8 @@ The design intentionally trades off some conceptual clarity around usage of
348347``await `` for improved performance.
349348Each time a task is awaited, control needs to be passed all the way up the
350349call stack to the event loop.
351- That might sound minor, but in a large program with many ``await ``'s  and a deep
352- callstack  that overhead can add up to a meaningful performance drag.
350+ That might sound minor, but in a large program with many ``await `` statements  and a deep
351+ call stack,  that overhead can add up to a meaningful performance drag.
353352
354353------------------------------------------------ 
355354A conceptual overview part 2: the nuts and bolts
@@ -372,7 +371,7 @@ resume a coroutine.
372371If the coroutine was paused and is now being resumed, the argument ``arg ``
373372will be sent in as the return value of the ``yield `` statement which originally
374373paused it.
375- If the coroutine is being used for the first time (as opposed to being resumed)
374+ If the coroutine is being used for the first time (as opposed to being resumed), 
376375``arg `` must be ``None ``.
377376
378377.. code-block ::
@@ -403,14 +402,14 @@ If the coroutine is being used for the first time (as opposed to being resumed)
403402       returned_value = e.value 
404403   print(f"Coroutine main() finished and provided value: {returned_value}.") 
405404
406- :ref: `yield  <yieldexpr >`, like  usual, pauses execution and returns control
405+ :ref: `yield  <yieldexpr >`, as  usual, pauses execution and returns control
407406to the caller.
408407In the example above, the ``yield ``, on line 3, is called by
409408``... = await rock `` on line 11.
410409More broadly speaking, ``await `` calls the :meth: `~object.__await__ ` method of
411410the given object.
412411``await `` also does one more very special thing: it propagates (or "passes
413- along") any ``yield ``\  s it receives up the call- chain.
412+ along") any ``yield ``\  s it receives up the call  chain.
414413In this case, that's back to ``... = coroutine.send(None) `` on line 16.
415414
416415The coroutine is resumed via the ``coroutine.send(42) `` call on line 21.
@@ -462,12 +461,12 @@ computation's status and result.
462461The term is a nod to the idea of something still to come or not yet happened,
463462and the object is a way to keep an eye on that something.
464463
465- A future has a few important attributes. One is its state which can be either
466- "pending", "cancelled" or "done".
464+ A future has a few important attributes. One is its state,  which can be either
465+ "pending", "cancelled",  or "done".
467466Another is its result, which is set when the state transitions to done.
468467Unlike a coroutine, a future does not represent the actual computation to be
469468done; instead, it represents the status and result of that computation, kind of
470- like a status light (red, yellow or green) or indicator.
469+ like a status light (red, yellow,  or green) or indicator.
471470
472471:class: `asyncio.Task ` subclasses :class: `asyncio.Future ` in order to gain
473472these various capabilities.
@@ -490,8 +489,8 @@ We'll go through an example of how you could leverage a future to create your
490489own variant of asynchronous sleep (``async_sleep ``) which mimics
491490:func: `asyncio.sleep `.
492491
493- This snippet registers a few tasks with the event loop and then awaits a 
494- coroutine wrapped in a task:  ``async_sleep(3) ``.
492+ This snippet registers a few tasks with the event loop and then awaits the task 
493+ created by `` asyncio.create_task ``, which wraps the  ``async_sleep(3) `` coroutine .
495494We want that task to finish only after three seconds have elapsed, but without
496495preventing other tasks from running.
497496
@@ -540,8 +539,8 @@ will monitor how much time has elapsed and, accordingly, call
540539       # Block until the future is marked as done. 
541540       await future 
542541
543- Below, we'll  use a rather bare object,  ``YieldToEventLoop() ``,  to ``yield ``
544- from ``__await__ `` in order to cede  control to the event loop.
542+ Below, we use a rather bare ``YieldToEventLoop() `` object  to ``yield ``
543+ from its  ``__await__ `` method, ceding  control to the event loop.
545544This is effectively the same as calling ``asyncio.sleep(0) ``, but this approach
546545offers more clarity, not to mention it's somewhat cheating to use
547546``asyncio.sleep `` when showcasing how to implement it!
@@ -552,13 +551,13 @@ The ``watcher_task``, which runs the coroutine ``_sleep_watcher(...)``, will
552551be invoked once per full cycle of the event loop.
553552On each resumption, it'll check the time and if not enough has elapsed, then
554553it'll pause once again and hand control back to the event loop.
555- Eventually,  enough time will have  elapsed, and  ``_sleep_watcher(...) `` will 
556- mark  the future as done,  and then itself finish too  by breaking out of the 
554+ Once  enough time has  elapsed, ``_sleep_watcher(...) ``
555+ marks  the future as done and completes  by exiting its 
557556infinite ``while `` loop.
558557Given this helper task is only invoked once per cycle of the event loop,
559558you'd be correct to note that this asynchronous sleep will sleep *at least *
560559three seconds, rather than exactly three seconds.
561- Note this is also of  true of ``asyncio.sleep ``.
560+ Note this is also true of ``asyncio.sleep ``.
562561
563562::
564563
@@ -601,6 +600,6 @@ For reference, you could implement it without futures, like so::
601600           else: 
602601               await YieldToEventLoop() 
603602
604- But,  that's all for now. Hopefully you're ready to more confidently dive into
603+ But that's all for now. Hopefully you're ready to more confidently dive into
605604some async programming or check out advanced topics in the
606605:mod: `rest of the documentation <asyncio> `.
0 commit comments