简体   繁体   中英

Asyncio python: How to call object methods in coroutines?

I'm currently trying to do something like this:

import asyncio

class Dummy:
    def method(self):
        return 1
    def __str__(self):
        return "THIS IS A DUMMY CLASS"

async def start_doing():
    asyncio.sleep(1)
    return Dummy


async def do_something():
    return start_doing().method()


async def main():
    a = asyncio.create_task(do_something())
    b = asyncio.create_task(do_something())

    results = await asyncio.gather(a, b)
    print(results)

asyncio.run(main())

But I get this error:

AttributeError: 'coroutine' object has no attribute 'method'

Which indicates that I cannot call my method on a coroutine object. One way to fix this is by doing these:

async def do_something():
    return (await start_doing()).method()

But I think that by doing this you are inherently making your code synchronous. You are not generating a future, rather waiting for your work to be finished in do_something and then proceed to the next item in the queue.

How should I call an object method in the future when the awaitable has been awaited and my object is ready? how to schedule it to be called in the future?

Await the call then call the method on an instance of the returned class.

async def start_doing():
    await asyncio.sleep(1)
    return Dummy


async def do_something():
    thing = await start_doing()
    return thing().method()

How should I call an object method in the future when the awaitable has been awaited and my object is ready? how to schedule it to be called in the future?

See if I can get this correct.

  • When you create the task do_something it is scheduled.
  • Eventually the event loop decides to let do_something start.
  • do_something calls start_doing and awaits it.
  • While do_something is waiting the event loop takes control away from it and lets something else have a turn.
  • At some points in time start_doing is scheduled, started, finishes waiting/sleeping, returns the object
    • during the waiting/sleeping part control may have been transferred to other tasks by the event loop
  • Eventually after do_something is done waiting the event loop gives control/focus back to it.
    • implies that other scheduled tasks have finished or are waiting on something.

I really don't know what the scheduling algorithm is, I think of it as a round-robin affair but it might be more intelligent than that.

To further extend on @wwii 's answer and address the concerns about risk of blocking using await you can play with functions like the following f :

import time
from datetime import datetime
import asyncio

start = datetime.now()

async def f(x, block_for=3):
    print(f"{x} IN     {ellapsed_time()}s")
    time.sleep(block_for)
    print(f"{x} AWAIT  {ellapsed_time()}s")
    await asyncio.sleep(x)
    print(f"{x} OUT    {ellapsed_time()}s")
    
def ellapsed_time():
    return (datetime.now() - start).seconds
    

asyncio.create_task(f(2))
asyncio.create_task(f(1))

Which produces:

2 IN     0s
2 AWAIT  3s
1 IN     3s
1 AWAIT  6s
2 OUT    6s
1 OUT    7s

Until await is called, f(2) is blocking (preventing any other task from being scheduled). Once we call await we explicitly inform the scheduler that we are waiting for something (usually I/O, but here simply "sleeping" ). Similarly, f(1) blocks f(2) from going out until it calls await .

If we remove the blocking part (block for 0s) f(1) will be rescheduled to execute before f(2) and will therefore finish first:

>>> start = datetime.now()
>>> asyncio.create_task(f(2, block_for=0))
>>> asyncio.create_task(f(1, block_for=0))

2 IN     0s
2 AWAIT  0s
1 IN     0s
1 AWAIT  0s
1 OUT    1s
2 OUT    2s

Finally, about this part:

… how to schedule it to be called in the future?

You can have a look at how is asyncio.sleep() in python implemented? , it will probably help you understand better how asynchronous programming work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM