将Blocking python函数转换为异步函数

j0pj023g  于 2023-02-02  发布在  Python
关注(0)|答案(1)|浏览(114)

所以现在我有4个API请求,它们是用第三方库同步调用的,我想要的是并行运行它们,这样我调用所有4个api的总时间就减少了。
我使用fastapi作为微框架。
utilities.py

async def get_api_1_data():
    data = some_third_party_lib()
    return data

async def get_api_2_data():
    data = some_third_party_lib()
    return data

async def get_api_3_data():
    data = some_third_party_lib()
    return data

async def get_api_4_data():
    data = some_third_party_lib()
    return data

我的main.py看起来像这样

import asyncio
from fastapi import FastAPI
app = FastAPI()

@app.get("/")
async def fetch_new_exposure_api_data(node: str):
   functions_to_run = [get_api_1_data(), get_api_2_data(), get_api_3_data(), get_api_4_data()]
   r1, r2, r3, r4 = await asyncio.gather(*functions_to_run)
   return [r1, r2, r3, r4]

所以问题是我不能把wait放在some_third_party_lib()的前面,因为它不是一个异步库,它是一个同步库,所以有没有什么方法可以把它们转换成异步功能来并行运行它们?

pbpqsu0x

pbpqsu0x1#

不幸的是,如果不改变同步函数的实现,就不能使它异步,如果some_third_party_lib()是同步函数,就不能使用asyncio库使它并行运行。
一种解决方法是在单独的 * 线程 * 中运行对some_third_party_lib()的每个调用。您可以使用 Python 中的concurrent.futures库来创建和管理 * 工作线程池 *。下面是我提出的示例设置:

import concurrent.futures

def get_api_1_data():
    return some_third_party_lib()

def get_api_2_data():
    return some_third_party_lib()

def get_api_3_data():
    return some_third_party_lib()

def get_api_4_data():
    return some_third_party_lib()

@app.get("/")
async def fetch_new_exposure_api_data(node: str):
    with concurrent.futures.ThreadPoolExecutor() as executor:
        results = [executor.submit(fn) for fn in [get_api_1_data, get_api_2_data, get_api_3_data, get_api_4_data]]

    return [result.result() for result in concurrent.futures.as_completed(results)]

这样,对some_third_party_lib()的每个调用将在单独的线程中运行,并且它们将并行运行。注意,返回列表中的结果顺序可能与functions_to_run列表中的函数顺序不匹配。

相关问题