How to create an asyncio object in python3?

Viewed 208

It's clear for my how I use asyncio in python3.

import asyncio
import time

async def do_something(number):
    print(f"do something no.{number} at timestamp      : {time.perf_counter():6.2f}")
    await asyncio.sleep(1)
    print(f"do something no.{number} ended at timestamp: {time.perf_counter():6.2f}")

async def main():
    await asyncio.gather(
        do_something(1),
        do_something(2)
    ) 

asyncio.run(main() )

However, I have no idea how I could create an own "await"-able object like asyncio.sleep. In this "await"-able I could encapsulate urllib.request, isn't it?

Can someone post an example? Many thanks.

2 Answers

You can await all coroutines, so any function with the prefix async is awaitable

For example:

import asyncio


async def some_function():
    await asyncio.sleep(1)
    print("Hello")


async def main():
    await some_function()


asyncio.run(main())

You can find some more information about coroutines at the python docs: https://docs.python.org/3/library/asyncio-task.html

Because urllib is blocking (does not allow other code to be running before it finishes) by default, it is not that easy to just "wrap" it in an awaitable function.

It is probably possible to offload it to something like another thread and then have an awaiable wait for that thread to finish, but it is probably easier to use an async web request library like aiohttp.

Please, take a look at this answer it uses old yield for-based syntax, but the idea stays the same: using asyncio.Future and loop.call_later() you can cast callback-based code into coroutine-based code:

import asyncio


async def my_sleep(delay):
    fut = asyncio.Future()

    loop = asyncio.get_event_loop()
    loop.call_later(
        delay,
        lambda *_: fut.set_result(True)
    )

    return await fut


async def main():
    await asyncio.gather(
        my_sleep(1),
        my_sleep(2),
        my_sleep(3)
    )
    print('ok')


asyncio.run(main())

I believe, urllib.request is blocking and doesn't provide callbacks so it can't be cast into coroutine-based form directly. A common way to handle the situation is to run it in async thread (see links in this answer).

But if you want just to make async http reqeust, forget all above and use aiohttp: it's created for the purpose.

Related