Python web框架中如何并发请求多个外部URL?
语言(python)
现在有这么一种情况。
web 框架 响应 来自客户端的请求的 handler 里面会返回一个列表记录 list1,
对于 list1 的第一个元素 ele1 要请求 url1,
list1 的第二个元素 ele2 要请求 url2,
以此类推,平均一个 url 请求要 200-300ms ,超时调成 1s
所以如果 list1 的长度为 10 的话,如果迭代请求的话,总时间为 5S 左右。
你们是怎么处理这种情况的?
Python web框架中如何并发请求多个外部URL?
那就并发请求然后 wait 到所有请求完成呗
在Python web框架里并发请求多个外部URL,最直接高效的方式是用asyncio配合aiohttp。如果你的框架本身支持异步(比如FastAPI、Sanic),或者你在用异步中间件,这方法最合适。下面是个在异步视图函数里用的例子:
import asyncio
import aiohttp
from fastapi import FastAPI
app = FastAPI()
async def fetch_url(session: aiohttp.ClientSession, url: str):
try:
async with session.get(url) as response:
return await response.text()
except Exception as e:
return f"Error fetching {url}: {e}"
@app.get("/fetch-multiple")
async def fetch_multiple_urls():
urls = [
"https://httpbin.org/get",
"https://api.github.com",
"https://jsonplaceholder.typicode.com/posts/1"
]
async with aiohttp.ClientSession() as session:
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return {"results": results}
如果你的项目是传统的同步框架(比如Flask、Django),并且不想动整体结构,可以用concurrent.futures的ThreadPoolExecutor来模拟并发。注意,这只是用线程池绕过GIL的I/O阻塞,不是真异步。
from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
from flask import Flask, jsonify
app = Flask(__name__)
def fetch_url_sync(url):
try:
return requests.get(url).text
except Exception as e:
return f"Error: {e}"
@app.route("/fetch-multiple")
def fetch_multiple():
urls = ["https://httpbin.org/get", "https://api.github.com"]
results = []
with ThreadPoolExecutor(max_workers=5) as executor:
future_to_url = {executor.submit(fetch_url_sync, url): url for url in urls}
for future in as_completed(future_to_url):
results.append(future.result())
return jsonify(results)
选异步方案还是线程池,主要看你项目的基础架构和需求。
这个时候适合用 tornado 的 ayncHttpClient 啦 http://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.AsyncHTTPClient
接受传入 loop, 非 tornado 框架也可以使用
比如
用 multiprocess?
gevent 的话用 grequests
如果你的框架是 tornado , 可以用它的 AsyncHttpClient
如果你的框架是 flask ,把这些 url 请求任务丢到 celery ,把请求情况保存到 redis ,所有请求都完成了再回调
并发请求之后合并结果
如果是因为网慢或者 response 大的话。。。即使请求并发了,结果还是快不起来
这种情况的话,我们一般用这个 [Go.IoT]( https://goiot.cc) 做一个中间件,
可以同时触发多个 http 请求,全都完成后执行下一步。
参考:[异步多线请求]( https://bb.goiot.cc/uploads/files/1487329416416-flow.png)
效果是你那种效果,难道 golang 也需要中间件来完成这种功能吗
当然不是。这个东东适用于那种需要经常更改的逻辑,如果是写好放在那很久都不会懂它,自然用原生的组件来完成会更漂亮,比如 golang 。
多线程也行啊


