如何在Python(asyncio)中创建一个可以在创建后启动的懒惰Future?

时间:2018-06-07 22:24:48

标签: python python-asyncio

我正试着用Python包围asyncio。我写了这个小程序,在调用时将首先打印

  

服务器启动

     

做一些叫做

的事情

然后一秒后

  

Async Thingy

这正是应该做的,但它还不是我想要的方式。

基本上,这会模仿Server想要在PeerPool中创建__init__的{​​{1}},这取决于ThingThatWeAreWaitingOn。我希望能够在PeerPool中创建__init__并传递Awaitable[ThingThatWeAreWaitingOn]PeerPool可以在准备好后立即使用ThingThatWeAreWaitingOn。同样,这似乎工作得很好,但问题是,正如现在的代码所示,我们开始直接从__init__内部解决run()的任务,但理想情况下我希望能够踢从import asyncio from typing import ( Awaitable, Any ) class ThingThatWeAreWaitingOn(): name = "Async Thingy" class PeerPool(): def __init__(self, discovery: Awaitable[ThingThatWeAreWaitingOn]): self.awaitable_discovery = discovery def do_stuff(self): print("Do stuff called") self.awaitable_discovery.add_done_callback(lambda d: print(d.result().name)) class Server(): def __init__(self): # This immediately kicks of the async task but all I want is to # create a Future to pass that would ideally be kicked off in # the run() method self.fut_discovery = asyncio.ensure_future(self.get_discovery()) self.peer_pool = PeerPool(self.fut_discovery) async def get_discovery(self): await asyncio.sleep(1) return ThingThatWeAreWaitingOn() def run(self): loop = asyncio.get_event_loop() print("Server booting") # Here is where I want to "kick off" the self.fut_discovery but how? # self.fut_discovery.kick_off_now() self.peer_pool.do_stuff() loop.run_forever() server = Server() server.run() 内部开始。

我该怎么做?

character

以下是可运行演示的链接:https://repl.it/repls/PleasedHeavenlyLock

1 个答案:

答案 0 :(得分:2)

如果我理解一切正确,你需要这样的东西:

class Server():    
    def __init__(self):
        self.fut_discovery = asyncio.Future()
        self.peer_pool = PeerPool(self.fut_discovery)

    async def get_discovery(self):
        await asyncio.sleep(1)
        return ThingThatWeAreWaitingOn()

    def run(self):
        loop = asyncio.get_event_loop()
        print("Server booting")

        async def discovery_done():
            res = await self.get_discovery()
            self.fut_discovery.set_result(res)
        asyncio.ensure_future(discovery_done())  # kick discovery to be done

        self.peer_pool.do_stuff()
        loop.run_forever()

您可能希望以某种方式重写代码以使其更清晰。现在,你不清楚你将要做什么以及哪部分代码取决于哪些。

例如,awaitable_discovery名称具有误导性:明确等待不需要add_done_callback方法。如果您正计划使用此方法,请签名

class PeerPool():
    def __init__(self, fut_discovery: asyncio.Future):

会更有意义。

可能你应该为发现创建一个类。您可以继承asyncio.Future或实施__await__ magic method,使其对象具有类似未来/等待的目标。