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())
当您在async
runner
中获得此结果时,您可以像这样等待结果:

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
的代码之间有一些方法可以实现某种程度的集成,但与您尝试的方式不同:请参阅和。