311 lines
7.1 KiB
Plaintext
Executable File
311 lines
7.1 KiB
Plaintext
Executable File
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Asyncio"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Asyncio is an asynchronous IO library for Python that utilises the async/await syntax . I was added to the standard library in Python 3.5. \n",
|
|
"\n",
|
|
"This is a simple over view. Asyncio and async/await isn't the the simplest, this is my take on it.\n",
|
|
"\n",
|
|
"There is more in-depth content in the Further Reading section bellow"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Synchronous vs Asynchronous"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"There are two ways of running code, synchronously; multiple tasks sequentially and asynchronously; multiple tasks concurrently."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Sync delay"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import time\n",
|
|
"\n",
|
|
"def syncsleep(delay):\n",
|
|
" print(\"Sleeping for {} seconds\".format(str(delay)))\n",
|
|
" time.sleep(delay)\n",
|
|
" print(\"Finished sleeping for {} seconds\".format(str(delay)))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"syncsleep(2)\n",
|
|
"syncsleep(1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Async delay"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import asyncio\n",
|
|
"\n",
|
|
"async def asyncsleep(delay):\n",
|
|
" print(\"Sleeping for {} seconds\".format(str(delay)))\n",
|
|
" await asyncio.sleep(delay)\n",
|
|
" print(\"Finished sleeping for {} seconds\".format(str(delay)))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"loop = asyncio.get_event_loop() \n",
|
|
"loop.create_task(asyncsleep(3))\n",
|
|
"loop.create_task(asyncsleep(2))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## What is it good for?\n",
|
|
"\n",
|
|
"Asyncio is good for IO bound code, including file and network IO.\n",
|
|
"\n",
|
|
"It is not good for CPU bound tasks, like mathematical computations or tightly bound loops.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Async Await"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Async and await are basicly fancy generators that we call coroutines. Coroutines are functions that can be paused, like generators. ```await``` is basicly the same as ```yeild from```"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Generators"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def fib(limit): \n",
|
|
" a, b = 0, 1\n",
|
|
" \n",
|
|
" while a < limit: \n",
|
|
" yield a \n",
|
|
" a, b = b, a + b \n",
|
|
" return \"Done\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"f = fib(10)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"f.__next__()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"for i in fib(5): \n",
|
|
" print(i) "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Event loop\n",
|
|
"\n",
|
|
"A coroutine can only called and awited by another coroutine. This causes a chicken and egg problem. \n",
|
|
"\n",
|
|
"To solve this problem an event loop is needed. Asyncio is an implemetation of an event loop. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## How it works\n",
|
|
"\n",
|
|
"Asyncio runs in a single thread, it uses cooperative mulitasking.\n",
|
|
"\n",
|
|
"A coroutine will pause while it waits for a result, giving controll back to the event loop. This allows other coroutines to run. \n",
|
|
"\n",
|
|
"When a result is received the event loop will pick it up and continue execution of the coroutine. \n",
|
|
"\n",
|
|
"Because a coroutine pauses and releases controll, data corruption isn't a problem like it is with threading."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Async Libraries\n",
|
|
"Functions used with asyncio need to be coroutines, awaitable, non-blocking. This causes a problem as most libraries aren't. Aiolibs is a collection of libraries that are. \n",
|
|
"\n",
|
|
"https://github.com/aio-libs\n",
|
|
"\n",
|
|
"There is a collection of libraries including, aiohttp; http client and server, aio{database}"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Aiohttp\n",
|
|
"https://github.com/aio-libs/aiohttp"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import aiohttp\n",
|
|
"import asyncio\n",
|
|
"\n",
|
|
"async def main():\n",
|
|
" async with aiohttp.ClientSession() as session:\n",
|
|
" async with session.get('http://localhost:8080') as resp:\n",
|
|
" print(resp.status)\n",
|
|
" print(await resp.text())\n",
|
|
"\n",
|
|
"\n",
|
|
"await main()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import asyncio\n",
|
|
"from aiofile import async_open\n",
|
|
"\n",
|
|
"\n",
|
|
"async def main():\n",
|
|
" async with async_open(\"hello.txt\", 'w+') as afp:\n",
|
|
" await afp.write(\"Hello \")\n",
|
|
" await afp.write(\"world\")\n",
|
|
" afp.seek(0)\n",
|
|
"\n",
|
|
" print(await afp.read())\n",
|
|
"\n",
|
|
" \n",
|
|
"loop = asyncio.get_event_loop()\n",
|
|
"loop.create_task(main())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Curio\n",
|
|
"https://curio.readthedocs.io/en/latest/"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Sources and Further Reading\n",
|
|
"\n",
|
|
"https://stackoverflow.com/questions/49005651/how-does-asyncio-actually-work/51116910#51116910\n",
|
|
"\n",
|
|
"https://realpython.com/async-io-python/\n",
|
|
"\n",
|
|
"https://realpython.com/python-concurrency/\n",
|
|
"\n",
|
|
"https://github.com/MagicStack/uvloop\n",
|
|
"\n",
|
|
"https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5/\n",
|
|
"\n",
|
|
"https://www.geeksforgeeks.org/generators-in-python/\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.8.5"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|