Python 如何从';阻塞功能';已经在循环中运行
希望下面的代码解释了我想做的比问题标题更好的事情Python 如何从';阻塞功能';已经在循环中运行,python,python-asyncio,Python,Python Asyncio,希望下面的代码解释了我想做的比问题标题更好的事情 import asyncio import time loop = asyncio.get_event_loop() class Foo(object): def __init__(self, num): self.num = num @property def number(self): # Somehow need to run get_number() in the loop.
import asyncio
import time
loop = asyncio.get_event_loop()
class Foo(object):
def __init__(self, num):
self.num = num
@property
def number(self):
# Somehow need to run get_number() in the loop.
number = self.get_number()
return number
@asyncio.coroutine
def get_number(self):
yield from loop.run_in_executor(None, time.sleep, self.num)
return self.num
@asyncio.coroutine
def runner(num):
print("getting Foo({})".format(num))
foo = Foo(num)
yield from asyncio.sleep(1)
print("accessing number property of Foo({})".format(num))
number = foo.number
print("Foo({}) number is {}".format(num, number))
tasks = [
asyncio.async(runner(3)),
asyncio.async(runner(1)),
]
go = loop.run_until_complete(asyncio.wait(tasks))
我不知道在注释所在的number
函数中该做什么。我尝试过各种各样的事情,但实际上我只是“把****扔到墙上,希望有东西能粘住”
这是一项后续行动。我想访问该属性,而不必执行来自的收益,因为我需要从模板(例如mako)访问该属性,并且让来自
的收益到处写入并不理想(考虑到mako可能是阻塞的,可能甚至不可能)。在一个完美的世界里,我会让这一切都以一个完美的方式运行
如果我想使用来自
的yield,代码将非常简单
class Foo(object):
def __init__(self, num):
self.num = num
@property
@asyncio.coroutine
def number(self):
yield from loop.run_in_executor(None, time.sleep, self.num)
return self.num
@asyncio.coroutine
def runner(num):
print("getting Foo({})".format(num))
foo = Foo(num)
yield from asyncio.sleep(1)
print("accessing number property of Foo({})".format(num))
number = yield from foo.number
print("Foo({}) number is {}".format(num, number))
#getting Foo(3)
#getting Foo(1)
#accessing number property of Foo(3)
#accessing number property of Foo(1)
#Foo(1) number is 1
#Foo(3) number is 3
我在主题中找到了,但我看不出添加已完成回调将如何与我的工作流配合使用。您要求的是不可能的,因为当您处于主线程中时(如果要调用foo.number
而不使用来自的收益,则需要显式地将控制权返回主循环。这正是yield from
所做的
如果不这样做,您需要在一个单独的线程中运行调用foo.number的函数,该线程将能够阻止(不从中产生)并等待get_number
的结果,而不会阻止阻止函数中的主循环,而不是返回计算值。您将返回asyncio.Future
:
return loop.create_task(self.get_number())
当您在asyncrunner
中获得此结果时,您可以像这样等待结果:
number = await foo.number
完整测试用例:
def test_future():
loop = asyncio.get_event_loop()
async def target(x: int) -> int:
loop.run_in_executor(None, time.sleep, 0.1)
return x + 1
def intermediate(x: int) -> asyncio.Future:
return loop.create_task(target(x))
async def main():
future = intermediate(5)
logger.debug('intermediate future = %r', future)
value = await future
assert value == 6
try:
loop.create_task(main())
loop.call_later(0.5, loop.stop)
loop.run_forever()
finally:
loop.close()
很抱歉,您要求的是不可能的事情。如果不从
中获得收益,就无法从协同程序中获取值。我的注释是。#不知何故需要运行get_number()在循环中。
是我希望创建未来任务并将其放入循环的地方,因此暂停当前函数-我只是不知道如何执行。例如,将number=self.get\u number()
更改为number=loop.create\u任务(self.get\u number())
。这是否可能?@neRok挂起当前正在运行的函数的唯一方法是使用从生成,这意味着它必须是一个协程。您可以使用循环将任务添加到事件循环。创建任务(self.get\u number())
,正如您所建议的,但在实际调用create\u task
的方法通过返回或调用从中获得的收益将控制权返回给事件循环之前,该任务不会实际执行。将基于的异步代码集成到同步代码中的方式无法实现oping.@neRok在同步和基于asyncio
的代码之间有一些方法可以实现某种程度的集成,但与您尝试的方式不同:请参阅和。