普通函数可以以异步方式调用,不过需要借助一些额外的工具或机制来实现。以下是几种常见的方法:
使用 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())