繁体   English   中英

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

[英]Asyncio python: How to call object methods in coroutines?

我目前正在尝试做这样的事情:

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

但我得到这个错误:

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

这表明我无法在协程 object 上调用我的方法。 解决此问题的一种方法是执行以下操作:

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

但我认为通过这样做,您本质上就是使您的代码同步。 您不是在生成未来,而是在do_something中等待您的工作完成,然后继续执行队列中的下一个项目。

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

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

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


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

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

看看我能不能把这个弄对。

  • 当您创建任务do_something时,它会被安排。
  • 最终,事件循环决定让do_something开始。
  • do_something调用start_doing并等待它。
  • do_something正在等待时,事件循环会从它那里拿走控制权并让其他东西轮流。
  • 在某些时间点start_doing被安排,开始,完成等待/睡眠,返回 object
    • 在等待/睡眠部分控制可能已被事件循环转移到其他任务
  • 最终在do_something完成等待之后,事件循环将控制/焦点返回给它。
    • 表示其他计划任务已完成或正在等待某事。

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

要进一步扩展@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

在调用await之前, 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() 是如何实现的? ,它可能会帮助您更好地理解异步编程是如何工作的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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