如何在 Python (asyncio) 中创建一个可以在创建后启动的惰性 Future?
How do I create a lazy Future in Python (asyncio) that can be kicked off after creation?
我正试图在 Python 中围绕 asyncio
思考。我写了这个小程序,调用时会先打印
Server booting
Do stuff called
一秒后
Async Thingy
这正是它应该做的,但还不是我想要的方式。
基本上这模仿了 Server
想要在 __init__
中创建一个 PeerPool
,这取决于 ThingThatWeAreWaitingOn
。我希望能够在 __init__
中创建 PeerPool
并传递一个 Awaitable[ThingThatWeAreWaitingOn]
以便 PeerPool
可以在准备就绪后立即使用。同样,这似乎工作得很好,但要注意的是,正如现在的代码一样,我们开始直接从 __init__
中解决 ThingThatWeAreWaitingOn
的任务,但理想情况下我希望能够踢从 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()
这是一个 link 可运行的演示:https://repl.it/repls/PleasedHeavenlyLock
如果我没看错的话,你想要这样的东西:
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
名称具有误导性:普通的 awaitable 没有必要具有 add_done_callback
方法。如果您打算使用此方法,请签名
class PeerPool():
def __init__(self, fut_discovery: asyncio.Future):
会更有意义。
也许您应该创建 class 以供发现。您可以继承 asyncio.Future
或实现 __await__
magic method 使其成为对象 future-like/awaitable.
我正试图在 Python 中围绕 asyncio
思考。我写了这个小程序,调用时会先打印
Server booting
Do stuff called
一秒后
Async Thingy
这正是它应该做的,但还不是我想要的方式。
基本上这模仿了 Server
想要在 __init__
中创建一个 PeerPool
,这取决于 ThingThatWeAreWaitingOn
。我希望能够在 __init__
中创建 PeerPool
并传递一个 Awaitable[ThingThatWeAreWaitingOn]
以便 PeerPool
可以在准备就绪后立即使用。同样,这似乎工作得很好,但要注意的是,正如现在的代码一样,我们开始直接从 __init__
中解决 ThingThatWeAreWaitingOn
的任务,但理想情况下我希望能够踢从 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()
这是一个 link 可运行的演示:https://repl.it/repls/PleasedHeavenlyLock
如果我没看错的话,你想要这样的东西:
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
名称具有误导性:普通的 awaitable 没有必要具有 add_done_callback
方法。如果您打算使用此方法,请签名
class PeerPool():
def __init__(self, fut_discovery: asyncio.Future):
会更有意义。
也许您应该创建 class 以供发现。您可以继承 asyncio.Future
或实现 __await__
magic method 使其成为对象 future-like/awaitable.