Python 异步之在 Asyncio中如何运行阻塞任务详解
作者:冷冻工厂 发布时间:2023-06-10 04:30:41
阻塞任务是阻止当前线程继续进行的任务。
如果在 asyncio 程序中执行阻塞任务,它会停止整个事件循环,从而阻止任何其他协程继续进行。
我们可以通过 asyncio.to_thread() 和 loop.run_in_executor() 函数在 asyncio 程序中异步运行阻塞调用。
1. 阻塞任务
asyncio的重点是异步编程和非阻塞IO。然而,我们经常需要在 asyncio 应用程序中执行阻塞函数调用。
这可能有很多原因,例如:
执行 CPU 密集型任务,例如计算某事。
执行阻塞 IO 绑定任务,如从文件读取或写入。
调用不支持 asyncio 的第三方库。
直接在 asyncio 程序中进行阻塞调用将导致事件循环在执行阻塞调用时停止。它不允许其他协程在后台运行。
我们如何在 asyncio 程序中异步执行阻塞调用?
2. 如何运行阻塞任务
asyncio 模块提供了两种在 asyncio 程序中执行阻塞调用的方法。
第一种是使用 asyncio.to_thread() 函数。这是在高级 API 中,供应用程序开发人员使用。
asyncio.to_thread() 函数采用要执行的函数名和任何参数。
该函数在单独的线程中执行。它返回一个可以作为独立任务等待或安排的协程。
...
# execute a function in a separate thread
await asyncio.to_thread(task)
在返回的协程有机会在事件循环中运行之前,任务不会开始执行。asyncio.to_thread() 函数在后台创建一个 ThreadPoolExecutor 来执行阻塞调用。因此,asyncio.to_thread() 函数仅适用于 IO 绑定任务。
另一种方法是使用 loop.run_in_executor() 函数。
这是在低级异步 API 中,首先需要访问事件循环,例如通过 asyncio.get_running_loop() 函数。
loop.run_in_executor() 函数接受一个执行器和一个要执行的函数。
如果没有为执行器提供,则使用默认执行器,即 ThreadPoolExecutor。
loop.run_in_executor() 函数返回一个可等待对象,如果需要可以等待它。任务将立即开始执行,因此返回的可等待对象不需要等待或安排阻塞调用开始执行。
...
# get the event loop
loop = asyncio.get_running_loop()
# execute a function in a separate thread
await loop.run_in_executor(None, task)
或者,可以创建一个执行器并将其传递给 loop.run_in_executor() 函数,该函数将在执行器中执行异步调用。
在这种情况下,调用者必须管理执行器,一旦调用者完成它就将其关闭。
...
# create a process pool
with ProcessPoolExecutor as exe:
# get the event loop
loop = asyncio.get_running_loop()
# execute a function in a separate thread
await loop.run_in_executor(exe, task)
# process pool is shutdown automatically...
这两种方法允许阻塞调用作为异步任务在 asyncio 程序中执行。
现在我们知道如何在 asyncio 程序中执行阻塞调用,让我们看一些有效的例子。
3. 实例
我们可以探索如何使用 asyncio.to_thread() 在 asyncio 程序中执行阻塞 IO 绑定调用。
在这个例子中,我们将定义一个函数来阻塞调用者几秒钟。然后,我们将使用 asyncio.to_thread() 函数在 asyncio 的线程池中异步执行此函数。
这将使呼叫者腾出时间继续其他活动。
# SuperFastPython.com
# example of running a blocking io-bound task in asyncio
import asyncio
import time
# a blocking io-bound task
def blocking_task():
# report a message
print('Task starting')
# block for a while
time.sleep(2)
# report a message
print('Task done')
# main coroutine
async def main():
# report a message
print('Main running the blocking task')
# create a coroutine for the blocking task
coro = asyncio.to_thread(blocking_task)
# schedule the task
task = asyncio.create_task(coro)
# report a message
print('Main doing other things')
# allow the scheduled task to start
await asyncio.sleep(0)
# await the task
await task
# run the asyncio program
asyncio.run(main())
运行示例首先创建 main() 协程并将其作为 asyncio 程序的入口点运行。main() 协程运行并报告一条消息。然后它发出对线程池的阻塞函数调用的调用。然后将协程包装在任务中并独立执行。
main() 协程可以自由地继续其他活动。在这种情况下,它会休眠片刻以允许计划任务开始执行。这使得目标函数可以在后台下发给 ThreadPoolExecutor 并开始运行。
然后 main() 协程挂起并等待任务完成。阻塞函数报告一条消息,休眠 2 秒,然后报告最后一条消息。
这突出了我们如何在一个单独的线程中与 asyncio 程序异步执行阻塞 IO 绑定任务。
Main running the blocking task
Main doing other things
Task starting
Task done
来源:https://juejin.cn/post/7205903144173748282
猜你喜欢
- CREATE OR REPLACE PROCEDURE PROCSENDEMAIL(P_TXT &
- 通常,我们会采用ORDER BY LIMIT start, offset 的方式来进行分页查询。例如下面这个SQL:SELECT * FRO
- 本文实例讲述了Python实现PS滤镜的万花筒效果。分享给大家供大家参考,具体如下:这里用 Python 实现 PS 的一种滤镜效果,称为万
- 由于工作需要本文主结合了excel表格,对表格中的ssh密码进行批量修改以下是详细代码(python3):'''遇到
- 有时候我们传.py文件给别人时,需要添加一些文件头注释。为了不用每次新建文件时都去手动添加作者、创建日期等信息,我们可以设置一套模板,在新建
- 本文实例为大家分享了Vue实现无限加载瀑布流的具体代码,供大家参考,具体内容如下我做的这个瀑布流放在了一个嵌套页面里,就是类似管理后台的ma
- 本文主要研究的是Python语言实现温度转换的相关实例,具体如下。代码如下:#TempConvert.py val=input("
- 数据库导入导出时总失败,错误信息如下: 正在验证 (错误) 消息 错误 0xc0202049: 数据流任务 1: 无法在只读列“ID”中插入
- 前言前面我们已经安装好了Docker,也简单了解了Docker。下面就来给大家介绍下Docker创建Mysql容器的简单步骤,话不多说了,来
- 首先我们来安装python1、首先进入网站下载:点击打开链接(或自己输入网址: https://www.python.org/downloa
- 优化数据库的注意事项:1、关键字段建立索引。2、使用存储过程,它使SQL变得更加灵活和高效。3、备份数据库和清除垃圾数据。4、SQL语句语法
- 数据备份与还原第二篇,具体如下基础概念:备份,将当前已有的数据或记录另存一份;还原,将数据恢复到备份时的状态。为什么要进行数据的备份与还原?
- 1、程序执行代码:#Author by Andy#_*_ coding:utf-8 _*_import os,sys,timeBase_di
- 本文实例讲述了Python中shape计算矩阵的方法。分享给大家供大家参考,具体如下:看到机器学习算法时,注意到了shape计算矩阵的方法接
- 在asp代码中分页是有点麻烦的事情,个人在在代码编写过程中把分页代码写成了两个函数,虽然在功能上不是很完善,但对于一般的应用应该是满足的了。
- Pyppeteer简介Puppeteer 是 Google 基于 Node.js 开发的一个工具,有了它我们可以通过 JavaScript
- 使用python爬虫其实就是方便,它会有各种工具类供你来使用,很方便。Java不可以吗?也可以,使用httpclient工具、还有一个大神写
- 这篇文章主要介绍了django 简单实现登录验证给你,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友
- Django RBAC权限管理概述RBAC(Role-Based Access Control,基于角色的访问控制),通过角色绑定权限,然后
- 跨数据库服务器,跨实例访问是比较常见的一种访问方式,在Oracle中可以通过DB LINK的方式来实现。对于MySQL而言,有一个FEDER