Python 试图了解任务如何与阻止调用一起工作

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之后说“你好

我最近开始研究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 输出:

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中添加的顶级方法相同的语义。