<jupyter_start><jupyter_text>Asyncio. One More TimePreviously about Async: [Coroutines-Into-the-Async.ipynb](../../lab09/demo/Coroutines-Into-the-Async.ipynb). Contents* [Sync vs. Async](sync-vs-async)  * [Sync](sync)  * [Kinda Async](kinda-async)  * [Still Kinda](kinda-async2)  * [Real Async](real-async)  * [...Even This Way](even-this-way)* [Coroutine vs. Future vs. Task](coroutine-vs-future-vs-task)  * [Coroutines](coroutines)  * [Futures](futures)  * [Tasks](tasks)* [Deeper Into Tasks](deeper-into-tasks)  * [Exceptions](exceptions)  * [Callbacks](callbacks)<jupyter_code>import asyncio

from typing import Awaitable


# Auxiliary library to work with asyncio in Jupyter Notebook

import nest_asyncio

nest_asyncio.apply()<jupyter_output><empty_output><jupyter_text>Sync vs. Async SyncBack to Contents<jupyter_code>def print_hello() -> None:
    print('Hello')


def print_world() -> None:
    print('World')
print_hello()
print_world()
del print_hello
del print_world<jupyter_output><empty_output><jupyter_text>Kinda AsyncBack to Contents<jupyter_code>async def print_hello_async() -> Awaitable[None]:
    print('Hello')


async def print_world_async() -> Awaitable[None]:
    print('World')
future1 = asyncio.ensure_future(print_hello_async())
future2 = asyncio.ensure_future(print_world_async())
del print_hello_async
del print_world_async
del future1
del future2<jupyter_output><empty_output><jupyter_text>Still KindaBack to Contents<jupyter_code>async def print_hello_async() -> Awaitable[None]:
    asyncio.sleep(1)  # Async sleep
    
    print('Hello')


async def print_world_async() -> Awaitable[None]:
    print('World')
future1 = asyncio.ensure_future(print_hello_async())
future2 = asyncio.ensure_future(print_world_async())<jupyter_output>D:\Maths\Anaconda3\envs\py7\lib\site-packages\ipykernel_launcher.py:2: RuntimeWarning: coroutine 'sleep' was never awaited
  
RuntimeWarning: Enable tracemalloc to get the object allocation traceback<jupyter_text>> coroutine 'sleep' was never awaited...🤔<jupyter_code>del print_hello_async
del print_world_async
del future1
del future2<jupyter_output><empty_output><jupyter_text>Real AsyncBack to Contents<jupyter_code>async def print_hello_async() -> Awaitable[None]:
    await asyncio.sleep(0.5)
    
    print('Hello')


async def print_world_async() -> Awaitable[None]:
    print('World')
future1 = asyncio.ensure_future(print_hello_async())
future2 = asyncio.ensure_future(print_world_async())
del print_hello_async
del print_world_async
del future1
del future2<jupyter_output><empty_output><jupyter_text>...Even This WayBack to Contents<jupyter_code>async def print_hello_async():
    await asyncio.sleep(0)  # No actual sleep!
    
    print('Hello')


async def print_world_async():
    print('World')
future1 = asyncio.ensure_future(print_hello_async())
future2 = asyncio.ensure_future(print_world_async())
del print_hello_async
del print_world_async
del future1
del future2<jupyter_output><empty_output><jupyter_text>Coroutine vs. Future vs. TaskBack to Contents<jupyter_code>async def print_hello_async() -> Awaitable[str]:
    await asyncio.sleep(1)
    
    message = 'Hello'
    
    print(message)
    
    return message


async def print_world_async() -> Awaitable[str]:
    await asyncio.sleep(0.1)

    message = 'World'
    
    print(message)
    
    return message<jupyter_output><empty_output><jupyter_text>CoroutinesBack to Contents<jupyter_code>coroutines = [
    print_hello_async(),
    print_world_async(),
]
loop = asyncio.get_event_loop()

loop.run_until_complete(
    asyncio.gather(*coroutines)
)
del coroutines<jupyter_output><empty_output><jupyter_text>FuturesBack to Contents<jupyter_code>coroutines = [
    print_hello_async(),
    print_world_async(),
]
# Registering tasks in the Event Loop

futures = [
    asyncio.ensure_future(coroutine)
    for coroutine in coroutines
]
# ...or right away like so

futures = [
    asyncio.ensure_future(print_hello_async()),
    asyncio.ensure_future(print_world_async()),
]
del coroutines
del futures<jupyter_output><empty_output><jupyter_text>TasksBack to ContentsSome task-related methods are available only starting from Python 3.7<jupyter_code>task1 = asyncio.create_task(print_hello_async())
task2 = asyncio.create_task(print_world_async())
# ..or like so

loop = asyncio.get_event_loop()

tasks = [
    loop.create_task(print_hello_async()),
    loop.create_task(print_world_async()),
]
del task1
del task2
del tasks<jupyter_output><empty_output><jupyter_text>Deeper into Tasks ExceptionsBack to Contents<jupyter_code>task = asyncio.create_task(print_hello_async())

print(task)
print(f'Is done? {task.done()}')
task
task.result()
task.done()<jupyter_output><empty_output><jupyter_text>Let's do something... illegal<jupyter_code>async def dangerous_deed_async() -> Awaitable[None]:
    await asyncio.sleep(1)
    
    1 / 0
task = asyncio.create_task(dangerous_deed_async())<jupyter_output><empty_output><jupyter_text>All Ok?!<jupyter_code>task
try:
    task.result()
except ZeroDivisionError:
    print('ZeroDivisionError error returned!')<jupyter_output>ZeroDivisionError error returned!<jupyter_text>Exception object:<jupyter_code>task.exception()<jupyter_output><empty_output><jupyter_text>Be careful )  CallbacksBack to Contents<jupyter_code>def callback(task):
    print('Task finished!')
    print(f'Result: {task.result()}')


task = asyncio.create_task(print_hello_async())
task.add_done_callback(callback)<jupyter_output>Hello
Task finished!
Result: Hello
{'fraction_non_alphanumeric': 0.11631282888767919, 'fraction_numerical': 0.006895300308473961, 'mean_word_length': 6.310344827586207, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '22248', 'license': 'MIT', 'n_tokens_mistral': 1947, 'n_tokens_neox': 1922, 'n_words': 338, 'path': 'labs/lab11/demo/Asyncio-One-More-Time.ipynb', 'repo_name': 'Alvant/AdvancedPython2020', 'size': '5511'}