Python 试图了解任务如何与阻止调用一起工作
我最近开始研究asyncio库,目标是用async替换一个基于线程的大型应用程序 在阅读asyncio时,我偶然发现了一个示例 正在使用create_任务。因为我现在还停留在Python3.6上,所以我用 ,生成当前代码: Python 3.6 导入异步 导入时间 异步def在延迟后说什么: printfstart{what}添加的内容可以更好地可视化正在发生的事情 等待asyncio.sleepdelay 打印什么 异步def主: task1=asyncio.sure\u未来 在1之后说“你好” task2=asyncio.sure\u未来 在2“世界”之后说 printfstarted于{time.strftime'%X'} 等待这两项任务完成后,应采取以下措施: 大约2秒。 等待任务1 等待任务2 打印在{time.strftime'%X'完成 如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu': 循环=异步IO.new\u事件\u循环 loop.run_直到_completemain loop.close 输出:Python 试图了解任务如何与阻止调用一起工作,python,asynchronous,python-3.6,python-asyncio,Python,Asynchronous,Python 3.6,Python Asyncio,我最近开始研究asyncio库,目标是用async替换一个基于线程的大型应用程序 在阅读asyncio时,我偶然发现了一个示例 正在使用create_任务。因为我现在还停留在Python3.6上,所以我用 ,生成当前代码: Python 3.6 导入异步 导入时间 异步def在延迟后说什么: printfstart{what}添加的内容可以更好地可视化正在发生的事情 等待asyncio.sleepdelay 打印什么 异步def主: task1=asyncio.sure\u未来 在1之后说“你好
started at 15:23:11
start hello
start world
hello
world
finished at 15:23:13
据我所知,事件循环:
首先启动任务task1;
点击asyncio.sleep后,它将上下文更改为第二个task2;和
当第一次睡眠结束时,它将更改为task1,同样,当其睡眠调用结束时,task2也会发生同样的情况。
综上所述,我的应用程序的一个要求是,我们需要将一些阻塞调用转换为协同路由。
我创建了此模拟代码,用于测试函数,目标如下:
Python 3.6
导入异步
导入时间
从concurrent.futures导入ThreadPoolExecutor
def正常_操作:
打印起始块
时间1
打印端块
异步定义异步\u操作:
打印启动非阻塞
等待asyncio.sleep2
打印端非阻塞
异步def主:
loop=asyncio.get\u事件\u循环
printfstarted于{time.strftime'%X'}
使用ThreadPoolExecutor作为池:
task1=asyncio.sure\u未来
loop.run\u在\u执行器池中,正常\u操作
task2=asyncio.sure\u未来
异步操作
等待任务1
等待任务2
打印在{time.strftime'%X'完成
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
循环=异步IO.new\u事件\u循环
loop.run_直到_completemain
loop.close
我希望输出类似于第一个示例,但当我运行此代码时,输出是:
started at 15:28:06
start blocking
ended blocking
start non blocking
ended non blocking
finished at 15:28:09
这两个函数按顺序运行,与第一个示例不同,在第一个示例中,启动打印调用一个接一个地调用
我不确定我做错了什么,我猜run_in_executor函数并没有真正创建异步调用,或者我只是实现了一个错误,我不知道。好的,我想是出错了 我在ThreadPoolExecutor外部等待非阻塞操作,在_exit __dunder中,正在使用wait=True参数调用一个shutdown函数,因此执行器基本上阻塞了我的代码 固定代码:
async def main():
loop = asyncio.get_event_loop()
print(f"started at {time.strftime('%X')}")
pool = ThreadPoolExecutor()
task1 = asyncio.ensure_future(loop.run_in_executor(pool, normal_operations))
task2 = asyncio.ensure_future(async_operation())
await task1
await task2
print(f"finished at {time.strftime('%X')}")
pool.shutdown(wait=True)
根据预期产出:
started at 16:20:48
start non blocking
start blocking
ended blocking
ended non blocking
finished at 16:20:50
没错。一个更简单的选项是将None作为第一个参数传递给run_in_executor,它将使用事件循环的默认executor作为ThreadPoolExecutor。在Python 3.6中,您可以在事件循环上使用create_任务方法,您可以通过调用get_event_loop获得该方法,该方法具有与3.7中添加的顶级方法相同的语义。