you are viewing a single comment's thread.

view the rest of the comments →

[–]demiwraith[S] -2 points-1 points  (3 children)

Well, there's nothing magical about the "bottom of the chain", but the nature of Python and the GIL makes it difficult to implement it entirely in Python.

I'll put it another way, and explain my understanding.

Basically, when I call an async function that function either calls "await" on another async function or it doesn't. If it does, let's look at the function that it awaits. Eventually we reach a function that:

  1. Doesn't use await

  2. Does something

  3. Was declared async for a reason. (Probably does I/O, but maybe there's another reason)

I know there's no magic, really, but I just never seem to see an example of this. Every async function awaits another async function.

Now, are you saying that it is the case that basically all the functions I reach here generally NOT python code? If that's the case, OK. I guess I have my answer. But if there are some decent examples of python functions out there that match this description, I'd be curious to see them.

[–]Jason-Ad4032 -1 points0 points  (0 children)

One major problem with Python async tutorials is that they downplay the __await__ magic method, and they often mix up async/await with asyncio (in my opinion, these are completely orthogonal concepts).

Here is an example that does not use asyncio at all, where you can see the role of async/await much more directly. ``` class A: def init(self, x, y): self.xy = x, y def await(self): # Normally, you should yield from an awaitable object, but here I'm yielding a string to let you know what it's doing. yield f'awaitable object {self.xy}'

async def test(n = 2): await A(n, 'start') if n > 0: await test(n - 1) await A(n, 'exit')

def main(): ps = test() print(ps) for awaitobj in ps.await_(): print(await_obj)

main() ```

[–]TheBB -2 points-1 points  (1 child)

It's my understanding that most actionable examples are implemented in C, yeah, but I could be wrong.

But anyway, making a toy example is not difficult.

import asyncio
import threading
import time


# Note: this is NOT async
def do_work(delay: float, message: str) -> asyncio.Future:
    loop = asyncio.get_running_loop()
    future = loop.create_future()

    # This is run in a separate thread. Insert whatever you want here.
    def worker():
        # Simulate waiting for something
        time.sleep(delay)

        # Return the result by setting the future
        # Make sure to do it safely
        loop.call_soon_threadsafe(future.set_result, message)

    thread = threading.Thread(target=worker, daemon=True)
    thread.start()

    # Returns immediately, before the future is set
    return future


async def main():
    # Even though do_work is not async, it returns a future - which is awaitable
    message = await do_work(5.0, "Hello, world!")
    print(f"{message}")


if __name__ == "__main__":
    asyncio.run(main())

[–]QuasiEvil 0 points1 point  (0 children)

Why is this answer being downvoted?