2

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 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the example. Would it be possible to use another function which contain the url request instead of the lambda-function? That would be pretty nice because the delay could work as a timeout.
@ThomasK no, lambda in the example above is only to mark some future done. It happens instantly. Regular blocking request would just block event loop. If you want async request - use aiohttp. If you want async timeout - use asyncio.wait_for, it has a timeout param.
1

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.

3 Comments

Thanks for your quick answer. :) "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." Yes, but this is exactly what I want to know and that's also the reason why I added the example with urllib. How would this look like?
@ThomasK I found this, idk if it still works but it seems to do something like what you wanted: gist.github.com/memee/66f85aea70f49489eb09
Thank you for the link, that's what I searched for. Do you know the difference to @Mikhail Gerasimov suggestion?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.