这是我第一次在这里发布问题,所以如果我错过了某些细节,请原谅我。如果需要,我会更新我的问题。 所以我想要的是能够在应用程序启动时下载大文件,但它应该并行发生。因为在实际的应用程序启动中不应等待文件下载完成。
我目前正在做的是
from fastapi import FastAPI
app = FastAPI()
items = {}
@app.on_event("startup")
def startup_event():
//Download file
现在这似乎有效,但我遇到了很多严重的工作超时错误。我想知道是否有某种方法可以在应用程序启动时进行下载,但又不会使应用程序等待下载完成。
例如,在启动时下载 10GB 文件 (https://speed.hetzner.de/10GB.bin)。
应用程序启动时,它会使用
aiohttp
触发异步下载任务,从 https://speed.hetzner.de/10GB.bin
获取文件并将其保存为 download_file。
下载以块的形式进行,此后台进程允许应用程序启动其他任务并响应传入请求,而无需等待下载完成。
import asyncio
from fastapi import FastAPI
import aiohttp
app = FastAPI()
async def download_large_file():
async with aiohttp.ClientSession() as session:
url = "https://speed.hetzner.de/10GB.bin"
async with session.get(url) as response:
if response.status == 200:
with open('downloaded_file', 'wb') as file:
while True:
chunk = await response.content.read(1024)
if not chunk:
break
file.write(chunk)
@app.on_event("startup")
async def startup_event():
loop = asyncio.get_event_loop()
loop.create_task(download_large_file())
希望这段代码有帮助。
此答案从之前回答的问题中得出代码和信息。因此,请查看以下答案以获取更多详细信息和解释:
下面提供的解决方案使用
httpx
库,该库为 Python 提供了强大的 HTTP 客户端库、async
API 并支持 HTTP/1.1 和 HTTP/2。 aiofiles
库还用于处理 asyncio
应用程序中的文件操作(例如将文件写入磁盘)。可以在此处找到用于测试解决方案的公共视频(大文件)。
如果您想在应用程序中重用 HTTP 客户端,请使用此解决方案。
from fastapi import FastAPI, Request
from contextlib import asynccontextmanager
import asyncio
import aiofiles
import httpx
async def download_large_file(client: httpx.AsyncClient):
large_file_url = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
path = 'save_to/video.mp4'
req = client.build_request('GET', large_file_url)
r = await client.send(req, stream=True)
async with aiofiles.open(path, 'wb') as f:
async for chunk in r.aiter_raw():
await f.write(chunk)
await r.aclose()
@asynccontextmanager
async def lifespan(app: FastAPI):
# Initialise the Client on startup and add it to the state
async with httpx.AsyncClient() as client:
asyncio.create_task(download_large_file(client))
yield {'client': client}
# The Client closes on shutdown
app = FastAPI(lifespan=lifespan)
@app.get('/home')
async def home():
return 'Hello World!'
如果您不需要重用 HTTP 客户端,而只需要在启动时使用它,请使用此解决方案。
from fastapi import FastAPI
from contextlib import asynccontextmanager
import asyncio
import aiofiles
import httpx
async def download_large_file():
large_file_url = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
path = 'save_to/video.mp4'
async with httpx.AsyncClient() as client:
async with client.stream('GET', large_file_url) as r:
async with aiofiles.open(path, 'wb') as f:
async for chunk in r.aiter_raw():
await f.write(chunk)
@asynccontextmanager
async def lifespan(app: FastAPI):
asyncio.create_task(download_large_file())
yield
app = FastAPI(lifespan=lifespan)
@app.get('/home')
async def home():
return 'Hello World!'