fastapi框架異步執(zhí)行踩坑記錄
fastapi框架異步執(zhí)行踩坑
問(wèn)題與背景
在公司項(xiàng)目中,使用了python作為中間件實(shí)現(xiàn)的主語(yǔ)言,項(xiàng)目是中間件性質(zhì)的需要并行的為第三方提供服務(wù),但是在使用過(guò)程中,出現(xiàn)了并行的問(wèn)題,多個(gè)耗時(shí)操作,在串行,導(dǎo)致項(xiàng)目的分析操作耗時(shí)巨大。
web技術(shù)采用的是fastapi,這個(gè)技術(shù)官網(wǎng)介紹是并行的,用java起多線程訪問(wèn)接口,得到的結(jié)論竟然是串行的,這地方就特意研究了一下。
最佳實(shí)踐
這篇文章,給我答疑解惑了:http://www.dbjr.com.cn/python/323052zd6.htm
我在項(xiàng)目中,翻了一個(gè)使用的錯(cuò)誤,類似的方式如下:
@router.get("/a") async def a(): time.sleep(1) return {"message": "異步模式,但是同步執(zhí)行sleep函數(shù),執(zhí)行過(guò)程是串行的"}
這種寫(xiě)法在于接口訪問(wèn)是異步的,但是執(zhí)行的時(shí)候卻是在主線程中,用同步的方法,就導(dǎo)致了串行了。
所以async和await應(yīng)該是成對(duì)出現(xiàn)的,否則就不是絕對(duì)的異步:
import asyncio @router.get("/b") async def b(): loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, time.sleep, 1) return {"message": "線程池中運(yùn)行sleep函數(shù)"}
這種方案接口可以異步調(diào)用,并且接口中的內(nèi)容也會(huì)被異步執(zhí)行,在實(shí)際使用中,可以對(duì)方法中的內(nèi)容進(jìn)行封裝,然后通過(guò)loop.run_in_executor去異步調(diào)用封裝的一個(gè)方法,最終實(shí)現(xiàn)絕對(duì)的異步。
fastapi的異步大騙/局
有部分入坑fastapi的同志們,可能經(jīng)常會(huì)遇到一個(gè)耗時(shí)的密集型IO任務(wù)阻塞主線程的情況,導(dǎo)致接口單個(gè)接口占用整體的線程時(shí)間過(guò)長(zhǎng),從而影響到其他的接口響應(yīng)。
很多人可能會(huì)說(shuō),fastapi不是一個(gè)異步的框架嗎?為什么會(huì)存在阻塞這個(gè)問(wèn)題?
這是一個(gè)很好的問(wèn)題,我之前也想過(guò)這個(gè)問(wèn)題,但是后面才發(fā)現(xiàn),原來(lái)是fastapi框架的接口,本身不會(huì)自動(dòng)幫忙處理長(zhǎng)耗時(shí)的任務(wù),如生成式的請(qǐng)求,調(diào)用復(fù)雜的第三方api,這個(gè)過(guò)程大概需要10-20s。
假如說(shuō)自己使用的http請(qǐng)求是直接requests庫(kù)的請(qǐng)求,那么就會(huì)導(dǎo)致阻塞。
正確的做法應(yīng)該是:
使用一個(gè)異步執(zhí)行的請(qǐng)求方式,例如aiohttp庫(kù),手動(dòng)為請(qǐng)求添加上這個(gè)異步的請(qǐng)求方法,我就是使用這個(gè)庫(kù)解決了長(zhǎng)耗時(shí)任務(wù)阻塞線程的問(wèn)題。
首先得安裝好這個(gè)庫(kù):
pip install aiohttp
然后就再代碼當(dāng)中
from fastapi import FastAPI import aiohttp import asyncio app = FastAPI() async def long_running_task(url: str): async with aiohttp.ClientSession() as session: async with session.post(url, json={"load": "data"}) as response: # 處理響應(yīng)數(shù)據(jù) data = await response.json() return data @app.post("/start_task/") async def start_task(): url = "http://example.com/api" # 目標(biāo) API 的 URL task_result = await long_running_task(url) return task_result
這樣,這個(gè)長(zhǎng)任務(wù)就不會(huì)阻塞主線程了。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Ubuntu下使用python讀取doc和docx文檔的內(nèi)容方法
今天小編就為大家分享一篇Ubuntu下使用python讀取doc和docx文檔的內(nèi)容方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05在Tensorflow中實(shí)現(xiàn)梯度下降法更新參數(shù)值
今天小編就為大家分享一篇在Tensorflow中實(shí)現(xiàn)梯度下降法更新參數(shù)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01Perl中著名的Schwartzian轉(zhuǎn)換問(wèn)題解決實(shí)現(xiàn)
這篇文章主要介紹了Perl中著名的Schwartzian轉(zhuǎn)換問(wèn)題解決實(shí)現(xiàn),本文詳解講解了Schwartzian轉(zhuǎn)換涉及的排序問(wèn)題,并同時(shí)給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06Python3.9環(huán)境搭建RobotFramework的詳細(xì)過(guò)程
Robot Framework是一個(gè)基于Python的,可擴(kuò)展的關(guān)鍵字驅(qū)動(dòng)的測(cè)試自動(dòng)化框架,用于端到端驗(yàn)收測(cè)試和驗(yàn)收測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(ATDD),這篇文章主要介紹了Python3.9環(huán)境搭建RobotFramework的詳細(xì)過(guò)程,需要的朋友可以參考下2023-01-01python爬蟲(chóng) requests-html的使用
這篇文章主要介紹了python爬蟲(chóng) requests-html的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11用Python刪除本地目錄下某一時(shí)間點(diǎn)之前創(chuàng)建的所有文件的實(shí)例
下面小編就為大家分享一篇用Python刪除本地目錄下某一時(shí)間點(diǎn)之前創(chuàng)建的所有文件的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12