-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
bpo-34831: Asyncio tutorial #9748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
16d3b94
Create basic structure of the asyncio tutorial
cjrh 50a901e
Begun work on the case study for the server
cjrh dfede40
Incorporate review comments from @willingc
cjrh a11e659
Refine language around threads and processes
cjrh 7e205d2
Incorporate message handling into server code
cjrh 7f2f149
Add message receiving to server code.
cjrh 61402e1
Added skeleton suggestions for the cookbook section
cjrh 550bdbf
Further notes in the cookbook
cjrh e7bc56d
Further work on describing how async def functions work
cjrh 3d4cdae
Fix review comment from @tirkarthi
cjrh e0bb48b
Fix typo
cjrh 5e4550a
Clarify the "What is async" section
cjrh 0de2748
Flesh out the sync-versus-async functions section
cjrh 89364f8
Add the blurb entry
cjrh be474f4
Remove TODOs
cjrh c403101
Write "Executing Async Functions"
cjrh 69190b8
Fix spurious backtick
cjrh 89f7ca2
Make the case study (server) a little neater.
cjrh 36fc743
Some refactoring and finishing off the server.
cjrh d55d8fb
Cleaned up the last bit of the c
8000
hat server code sample.
cjrh 34306f0
Further progress - got a CLI chat client working using prompt-toolkit.
cjrh 0c82755
Include chat client code in the text.
cjrh a774a98
Fix typo
cjrh eedbc97
Clarify switching behaviour
cjrh a8a801d
Add async generators and async context managers discussion.
cjrh 8e6dcfd
Add some comparison with JavaScript async/await and asyncio.create_task
cjrh 0e5ed3f
Fix "no good read" typo
cjrh 4714ed2
Fix "do not required" typo
cjrh d71da67
Modern -> modern
cjrh 26cc634
Removing the GUI case study section
cjrh 9530021
Remove problematic backticks inside a code-block
cjrh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8000 div>
Added skeleton suggestions for the cookbook section
- Loading branch information
commit 61402e1352b7eaec2a6e3fb231ac379628e03119
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,215 @@ Asyncio Cookbook | |
Let's look at a few common situations that will come up in your | ||
``asyncio`` programs, and how best to tackle them. | ||
|
||
[There's a lot more we can do if we're able to refer to | ||
3rd party packages here. We could show a websockets example, | ||
and other things.] | ||
|
||
Using A Queue To Move Data Between Long-Lived Tasks | ||
--------------------------------------------------- | ||
|
||
TODO | ||
|
||
Using A Queue To Control A Pool of Resources | ||
-------------------------------------------- | ||
|
||
- show example with a pool of workers | ||
- show example with a connection pool | ||
|
||
Keeping Track Of Many Connections | ||
--------------------------------- | ||
|
||
- example using a global dict | ||
- show how a weakref container can simplify cleanup | ||
- show how to access connection info e.g. ``get_extra_info()`` | ||
- this kind of thing: | ||
|
||
.. code-block:: python3 | ||
|
||
import asyncio | ||
from weakref import WeakValueDictionary | ||
|
||
CONNECTIONS = WeakValueDictionary() | ||
|
||
async def client_connected_cb(reader, writer): | ||
|
||
addr = writer.get_extra_info('peername') | ||
print(f'New connection from {addr}') | ||
|
||
# Every new connection gets added to the global dict. | ||
# Actually, *writer* objects get added. This makes | ||
# it easy to look up a connection and immediately | ||
# send data to it from other async functions. | ||
CONNECTIONS[addr] = writer | ||
... | ||
|
||
async def main(): | ||
server = await asyncio.start_server( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New API:
|
||
client_connected_cb=client_connected_db, | ||
host='localhost', | ||
port='9011', | ||
) | ||
async with server: | ||
await server.serve_forever() | ||
|
||
if __name__ == '__main__': | ||
asyncio.run(main()) | ||
|
||
Handling Reconnection | ||
--------------------- | ||
|
||
- Example is a client app that needs to reconnect to a server | ||
if the server goes down, restarts, or there is a network partition | ||
or other general kind of error | ||
|
||
Async File I/O | ||
-------------- | ||
|
||
- mention that disk I/O is still IO | ||
- Python file operations like ``open()``, etc. are blocking | ||
- I think all we can do here is refer to the 3rd party *aiofiles* | ||
package? | ||
- I suppose we could show how to do file IO in thread, driven | ||
by ``run_in_executor()``... | ||
|
||
Wait For Async Results In Parallel | ||
---------------------------------- | ||
|
||
TODO | ||
|
||
- show an example with gather | ||
- show another example with wait | ||
- maybe throw in an example with gather that also uses | ||
"wait_for" for timeout | ||
- either include "return_exceptions" here or in a different question | ||
|
||
.. code-block:: python3 | ||
|
||
import asyncio | ||
|
||
async def slow_sum(x, y): | ||
result = x + y | ||
await asyncio.sleep(result) | ||
return result | ||
|
||
async def main(): | ||
results = await asyncio.gather( | ||
slow_sum(1, 1), | ||
slow_sum(2, 2), | ||
) | ||
print(results) # "[2, 4]" | ||
|
||
if __name__ == '__main__': | ||
asyncio.run(main()) | ||
|
||
Secure Client-Server Networking | ||
------------------------------- | ||
|
||
- built-in support for secure sockets | ||
- you have to make your own secret key, and server certificate | ||
|
||
.. code-block:: bash | ||
:caption: Create a new private key and certificate | ||
|
||
$ openssl req -newkey rsa:2048 -nodes -keyout chat.key \ | ||
-x509 -days 365 -out chat.crt | ||
|
||
This creates ``chat.key`` and ``chat.crt`` in the current dir. | ||
|
||
.. code-block:: python3 | ||
:caption: Secure server | ||
|
||
import asyncio | ||
import ssl | ||
|
||
async def main(): | ||
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) | ||
ctx.check_hostname = False | ||
|
||
# These must have been created earlier with openssl | ||
ctx.load_cert_chain('chat.crt', 'chat.key') | ||
|
||
server = await asyncio.start_server( | ||
client_connected_cb=client_connected_cb, | ||
host='localhost', | ||
port=9011, | ||
ssl=ctx, | ||
) | ||
async with server: | ||
await server.serve_forever() | ||
|
||
async def client_connected_cb(reader, writer): | ||
print('Client connected') | ||
received = await reader.read(1024) | ||
while received: | ||
print(f'received: {received}') | ||
received = await reader.read(1024) | ||
|
||
if __name__ == '__main__': | ||
asyncio.run(main()) | ||
|
||
|
||
.. code-block:: python3 | ||
:caption: Secure client | ||
|
||
import asyncio | ||
import ssl | ||
|
||
async def main(): | ||
print('Connecting...') | ||
ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) | ||
ctx.check_hostname = False | ||
|
||
# The client must only have access to the cert *not* the key | ||
ctx.load_verify_locations('chat.crt') | ||
reader, writer = await asyncio.open_connection( | ||
host='localhost', | ||
port=9011, | ||
ssl=ctx | ||
) | ||
|
||
writer.write(b'blah blah blah') | ||
await writer.drain() | ||
writer.close() | ||
await writer.wait_closed() | ||
|
||
if __name__ == '__main__': | ||
asyncio.run(main()) | ||
|
||
Correctly Closing Connections | ||
----------------------------- | ||
|
||
- from the client side | ||
- from the server side | ||
|
||
Handling Typical Socket Errors | ||
------------------------------ | ||
|
||
- Maybe describe the situations in which they can occur? Not sure. | ||
|
||
- ``ConnectionError`` | ||
- ``ConnectionResetError`` | ||
- ``ConnectionAbortedError`` | ||
- ``ConnectionRefusedError`` | ||
|
||
Might also want to show some examples of ``asyncio.IncompleteReadError``. | ||
|
||
Graceful Shutdown on Windows | ||
---------------------------- | ||
|
||
TODO | ||
|
||
|
||
Run A Blocking Call In An Executor | ||
---------------------------------- | ||
|
||
- show example with default executor | ||
- show example with a custom executor (thread-based) | ||
- show example with a custom executor (process-based) | ||
|
||
|
||
|
||
|
||
Notes: | ||
|
||
- My thinking here was a Q&A style, and then each section has | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO?