异步函数中调用普通函数

普通函数可以以异步方式调用,不过需要借助一些额外的工具或机制来实现。以下是几种常见的方法:

使用 asyncio.to_thread(Python 3.9+)

asyncio.to_thread 函数可以将普通函数包装成一个异步函数,在新的线程中执行该普通函数,从而实现异步调用。示例代码如下:

import asyncio
import time

def sync_function():
    time.sleep(2)
    print("同步函数执行完毕")

async def main():
    print("开始执行异步函数")
    await asyncio.to_thread(sync_function)
    print("异步函数执行完毕")

asyncio.run(main())

使用 ThreadPoolExecutor

可以手动创建一个线程池 ThreadPoolExecutor,并使用 loop.run_in_executor 方法在线程池中执行普通函数,达到异步调用的效果。示例如下:

import asyncio
from concurrent.futures import ThreadPoolExecutor
import time

def sync_function():
    time.sleep(2)
    print("同步函数执行完毕")

async def main():
    print("开始执行异步函数")
    loop = asyncio.get_event_loop()
    executor = ThreadPoolExecutor()
    await loop.run_in_executor(executor, sync_function)
    print("异步函数执行完毕")

asyncio.run(main())

使用 asyncio.create_task 结合协程函数包装

可以将普通函数包装在一个协程函数中,然后使用 asyncio.create_task 来创建一个异步任务并执行。示例代码如下:

import asyncio
import time

def sync_function():
    time.sleep(2)
    print("同步函数执行完毕")

async def async_wrapper():
    sync_function()

async def main():
    print("开始执行异步函数")
    task = asyncio.create_task(async_wrapper())
    await task
    print("异步函数执行完毕")

asyncio.run(main())

虽然这些方法可以实现普通函数的异步调用,但要注意线程安全问题,避免多个线程同时访问和修改共享资源导致数据不一致等问题。

使用装饰器

import asyncio
from functools import wraps

def async_decorator(func):
    @wraps(func)
    async def wrapper(*args, **kwargs):
        loop = asyncio.get_event_loop()
        # 使用线程池执行器来运行普通函数
        return await loop.run_in_executor(None, lambda: func(*args, **kwargs))
    return wrapper

# 普通函数
def sync_function(x, y):
    return x + y

# 使用装饰器将普通函数转换为异步函数
async_function = async_decorator(sync_function)

async def main():
    result = await async_function(3, 5)
    print(result)

asyncio.run(main())
使用 Hugo 构建
主题 StackJimmy 设计