Python 异步运行或运行\u直到\u完成
我以一种非常基本的方式为应用程序使用Python 异步运行或运行\u直到\u完成,python,python-asyncio,Python,Python Asyncio,我以一种非常基本的方式为应用程序使用asyncio。通过查看internet上的大多数教程(甚至是官方文档),我发现它们使用了get\u event\u loop()和循环 导入异步IO 异步定义所说的(什么,何时): 等待asyncio.sleep(何时) 打印(什么) loop=asyncio.get\u event\u loop() 循环。运行_直到_完成(说('helloworld',1)) loop.close() 但在这本书中,我们可以读到: 应用程序开发人员通常应该使用高级异步I
asyncio
。通过查看internet上的大多数教程(甚至是官方文档),我发现它们使用了get\u event\u loop()
和循环
导入异步IO
异步定义所说的(什么,何时):
等待asyncio.sleep(何时)
打印(什么)
loop=asyncio.get\u event\u loop()
循环。运行_直到_完成(说('helloworld',1))
loop.close()
但在这本书中,我们可以读到:
应用程序开发人员通常应该使用高级异步IO函数,例如,并且应该很少需要引用循环对象或调用其方法。本节主要针对低级别代码、库和框架的作者,他们需要更好地控制事件循环行为
我发现它更干净、更易于使用,但它只适用于Python3.7+。因此,在这里我必须做出选择,是使用Python3.7+和run()
,还是使其与Python3.6兼容并使用事件循环。你将如何处理这个问题?是否有一种简单的方法使其向后兼容Python 3.6?在Python3.7成为一个通用版本之前,我是否应该首先检查Python版本,并在此基础上使用一种或另一种方法
有没有一种简单的方法使[代码使用asyncio.run
]向后兼容Python 3.6
您可以实现asyncio的一个简单替代品。运行
并在较旧的Python版本上调用它:
import asyncio, sys, types
def run(coro):
if sys.version_info >= (3, 7):
return asyncio.run(coro)
# Emulate asyncio.run() on older versions
# asyncio.run() requires a coroutine, so require it here as well
if not isinstance(coro, types.CoroutineType):
raise TypeError("run() requires a coroutine object")
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(coro)
finally:
loop.close()
asyncio.set_event_loop(None)
与只使用
loop.run_直到_complete()
相比,这种方法的优势在于,即使在较旧的Python版本上,您也可以使用与新的asyncio.run
相近的语义来执行代码。(例如,您将始终在新创建的事件循环上运行。)放弃对3.7版之前Python的支持将非常简单,只需删除run
垫片并直接调用asyncio.run
。通过从asyncio.runners.py复制代码,就可以复制asyncio.run
。下面的一个来自Python 3.8
from asyncio import coroutines, events, tasks
def run(main, *, debug=False):
"""Execute the coroutine and return the result.
This function runs the passed coroutine, taking care of
managing the asyncio event loop and finalizing asynchronous
generators.
This function cannot be called when another asyncio event loop is
running in the same thread.
If debug is True, the event loop will be run in debug mode.
This function always creates a new event loop and closes it at the end.
It should be used as a main entry point for asyncio programs, and should
ideally only be called once.
Example:
async def main():
await asyncio.sleep(1)
print('hello')
asyncio.run(main())
"""
if events._get_running_loop() is not None:
raise RuntimeError(
"asyncio.run() cannot be called from a running event loop")
if not coroutines.iscoroutine(main):
raise ValueError("a coroutine was expected, got {!r}".format(main))
loop = events.new_event_loop()
try:
events.set_event_loop(loop)
loop.set_debug(debug)
return loop.run_until_complete(main)
finally:
try:
_cancel_all_tasks(loop)
loop.run_until_complete(loop.shutdown_asyncgens())
finally:
events.set_event_loop(None)
loop.close()
def _cancel_all_tasks(loop):
to_cancel = tasks.all_tasks(loop)
if not to_cancel:
return
for task in to_cancel:
task.cancel()
loop.run_until_complete(
tasks.gather(*to_cancel, loop=loop, return_exceptions=True))
for task in to_cancel:
if task.cancelled():
continue
if task.exception() is not None:
loop.call_exception_handler({
'message': 'unhandled exception during asyncio.run() shutdown',
'exception': task.exception(),
'task': task,
})
如果你要编写更复杂的代码,在两个版本上都能工作,在新版本上更简单的代码,并且你会在它们之间动态切换……那么简单地使用一个更复杂的代码,在两个版本上都能工作,不是更容易吗?@deceze是的,也许这是最好的选择,我想对此有一个看法,如果要使它兼容,我想知道哪种方法是最好的so@deceze在较旧的Python版本上模拟
asyncio.run
,并不困难,而且您可以在asyncio.run
设置的条件下测试代码,即在新创建的事件循环上。很好!这看起来很棒!我会试试这个:)谢谢!只是代码中的一个小问题,条件应该是sys.version\u info>=(3,7)
。谢谢你的帮助!:)超级的!谢谢!