我可能需要帮助更好地表达这个问题。我正在通过 python3.7 和一个类(名为 Worker()
)编写一个异步 api 接口(interface)。 Worker
我想使用 loop.run_in_executor()
运行一些阻止方法。
我想构建一个装饰器,我可以将其添加到所有非 async
之上。 Worker
中的方法,但我不断遇到问题。
我被告知我需要await
wraps()
在下面的装饰器中:
def run_method_in_executor(func, *, loop=None):
async def wraps(*args):
_loop = loop if loop is not None else asyncio.get_event_loop()
return await _loop.run_in_executor(executor=None, func=func, *args)
return wraps
返回:
RuntimeWarning: coroutine 'run_method_in_executor.<locals>.wraps' was never awaited
我不知道如何正确地 await
wraps()
因为包含函数和修饰函数不是异步的。不确定这是否是由于误解造成的asyncio
,或误解装饰器。
任何帮助(或帮助澄清)将不胜感激!
最佳答案
这里是 Python 3.6+ 的完整示例,它不使用 3.8 弃用的接口(interface)。返回loop.run_in_executor
的值可以有效地将包装函数转换为在线程中执行的awaitable,因此您可以等待
它的完成。
#!/usr/bin/env python3
import asyncio
import functools
import time
def run_in_executor(_func):
@functools.wraps(_func)
def wrapped(*args, **kwargs):
loop = asyncio.get_event_loop()
func = functools.partial(_func, *args, **kwargs)
return loop.run_in_executor(executor=None, func=func)
return wrapped
@run_in_executor
def say(text=None):
"""Block, then print."""
time.sleep(1.0)
print(f'say {text} at {time.monotonic():.3f}')
async def main():
print(f'beginning at {time.monotonic():.3f}')
await asyncio.gather(say('asdf'), say('hjkl'))
await say(text='foo')
await say(text='bar')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
beginning at 3461039.617
say asdf at 3461040.618
say hjkl at 3461040.618
say foo at 3461041.620
say bar at 3461042.621
关于python - 是否可以让装饰器在 asyncio 执行器中运行阻塞函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55052883/