为了账号安全,请及时绑定邮箱和手机立即绑定

Asyncio python:如何在协程中调用对象方法?

Asyncio python:如何在协程中调用对象方法?

繁星点点滴滴 2023-02-07 16:55:58
我目前正在尝试做这样的事情:import asyncioclass Dummy:    def method(self):        return 1    def __str__(self):        return "THIS IS A DUMMY CLASS"async def start_doing():    asyncio.sleep(1)    return Dummyasync 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())但我收到此错误:AttributeError: 'coroutine' object has no attribute 'method'这表明我无法在协程对象上调用我的方法。解决此问题的一种方法是执行以下操作:async def do_something():    return (await start_doing()).method()但我认为这样做本质上就是让代码同步。你不是在创造未来,而是在等待你的工作完成do_something,然后继续处理队列中的下一项。awaitable当已经等待并且我的对象准备好时,我应该如何在将来调用对象方法?如何安排它在未来被调用?
查看完整描述

2 回答

?
达令说

TA贡献1821条经验 获得超6个赞

等待调用,然后在返回类的实例上调用该方法。


async def start_doing():

    await asyncio.sleep(1)

    return Dummy



async def do_something():

    thing = await start_doing()

    return thing().method()

当等待对象已经等待并且我的对象已准备好时,我应该如何在将来调用对象方法?如何安排它在未来被调用?


看看我能不能弄对。


当您创建任务do_something时,它会被安排。

最终事件循环决定让我们do_something开始。

do_something呼叫start_doing并等待它。

在do_something等待的过程中,事件循环将控制权从它手中夺走,让其他事情发生。

在某些时间点start_doing被调度,开始,完成等待/休眠,返回对象

在等待/睡眠部分控制可能已通过事件循环转移到其他任务

最终在do_something等待事件循环完成后将控制权/焦点交还给它。

暗示其他计划任务已经完成或正在等待某事。

我真的不知道调度算法是什么,我认为它是一个循环事件,但它可能比这更智能。


查看完整回答
反对 回复 2023-02-07
?
动漫人物

TA贡献1815条经验 获得超10个赞

要进一步扩展@wwii答案并解决有关阻塞风险的担忧,await您可以使用以下功能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))

哪个产生:


2 IN     0s

2 AWAIT  3s

1 IN     3s

1 AWAIT  6s

2 OUT    6s

1 OUT    7s

Untilawait被调用,f(2)正在阻塞(阻止任何其他任务被调度)。一旦我们调用await,我们就明确地通知调度程序我们正在等待某事(通常是 I/O,但这里只是“睡眠”)。类似地,在它调用之前f(1)阻止f(2)出去await。


如果我们删除阻塞部分(阻塞 0s)f(1)将被重新安排到执行之前f(2),因此将首先完成:


>>> 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

最后,关于这部分:


......如何安排它在未来被调用?


你可以看看python中的asyncio.sleep()是怎么实现的?,它可能会帮助您更好地理解异步编程的工作原理。


查看完整回答
反对 回复 2023-02-07
  • 2 回答
  • 0 关注
  • 121 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号