使用 Quart (Flask 的异步版本) 和 FastAPI 构建异步服务

Flask (使用 Quart) 服务器端代码

pip install quart pydantic


服务器端

from quart import Quart, jsonify, request
from pydantic import BaseModel, ValidationError, conint
import logging
import asyncio
import uuid
from datetime import datetime

# 创建 Quart 应用实例
app = Quart(__name__)

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 定义请求数据模型
class RequestModel(BaseModel):
    count: conint(ge=1, le=1000)  # count 必须在 1 到 1000 之间

@app.route('/data', methods=['GET', 'POST'])
async def get_data():
    try:
        if request.method == 'GET':
            # 处理 GET 请求参数并进行验证
            params = request.args
        else:
            # 处理 POST 请求参数并进行验证
            if request.content_type == 'application/json':
                params = await request.json
            else:
                params = await request.form

        data = RequestModel(count=int(params.get('count', 100)))

        # 异步操作 1,例如数据库查询
        async def fetch_data_1():
            await asyncio.sleep(1)
            return {'data_1': list(range(data.count))}

        # 异步操作 2,例如外部 API 调用
        async def fetch_data_2():
            await asyncio.sleep(1)
            return {'data_2': list(range(data.count, data.count * 2))}

        # 并行执行异步操作
        result_1, result_2 = await asyncio.gather(fetch_data_1(), fetch_data_2())

        # 构建响应数据
        response_data = {
            'message': 'Hello, this is async data!',
            'result_1': result_1,
            'result_2': result_2,
            'metadata': {
                'request_id': str(uuid.uuid4()),
                'timestamp': datetime.utcnow().isoformat()
            }
        }
        return jsonify(response_data)
    except ValidationError as ve:
        logger.warning(f"Validation error: {ve}")
        return jsonify({'error': ve.errors()}), 400
    except Exception as e:
        logger.error(f"Server error: {e}")
        return jsonify({'error': 'Internal Server Error'}), 500

# 定义错误处理程序
@app.errorhandler(404)
async def page_not_found(e):
    return jsonify({'error': 'Not Found'}), 404

# 运行应用
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)



FastAPI 服务器端代码

pip install fastapi uvicorn pydantic


服务器端

from fastapi import FastAPI, HTTPException, Request, Form
from fastapi.responses import JSONResponse
from pydantic import BaseModel, conint
import logging
import asyncio
import uuid
from datetime import datetime
from typing import Union

# 创建 FastAPI 应用实例
app = FastAPI()

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# 定义请求数据模型
class RequestModel(BaseModel):
    count: conint(ge=1, le=1000)  # count 必须在 1 到 1000 之间

@app.get("/data")
async def get_data(count: int = 100):
    try:
        # 验证请求参数
        data = RequestModel(count=count)

        # 异步操作 1,例如数据库查询
        async def fetch_data_1():
            await asyncio.sleep(1)
            return {'data_1': list(range(data.count))}

        # 异步操作 2,例如外部 API 调用
        async def fetch_data_2():
            await asyncio.sleep(1)
            return {'data_2': list(range(data.count, data.count * 2))}

        # 并行执行异步操作
        result_1, result_2 = await asyncio.gather(fetch_data_1(), fetch_data_2())

        # 构建响应数据
        response_data = {
            'message': 'Hello, this is async data!',
            'result_1': result_1,
            'result_2': result_2,
            'metadata': {
                'request_id': str(uuid.uuid4()),
                'timestamp': datetime.utcnow().isoformat()
            }
        }
        return JSONResponse(content=response_data)
    except HTTPException as he:
        logger.warning(f"Client error: {he.detail}")
        raise he
    except Exception as e:
        logger.error(f"Server error: {e}")
        raise HTTPException(status_code=500, detail="Internal Server Error")

@app.post("/data")
async def post_data(request: Request, count: Union[int, None] = Form(None)):
    try:
        if request.headers['content-type'] == 'application/json':
            params = await request.json()
        else:
            params = await request.form()
        
        if count is None:
            count = int(params.get('count', 100))
        
        data = RequestModel(count=count)

        # 异步操作 1,例如数据库查询
        async def fetch_data_1():
            await asyncio.sleep(1)
            return {'data_1': list(range(data.count))}

        # 异步操作 2,例如外部 API 调用
        async def fetch_data_2():
            await asyncio.sleep(1)
            return {'data_2': list(range(data.count, data.count * 2))}

        # 并行执行异步操作
        result_1, result_2 = await asyncio.gather(fetch_data_1(), fetch_data_2())

        # 构建响应数据
        response_data = {
            'message': 'Hello, this is async data!',
            'result_1': result_1,
            'result_2': result_2,
            'metadata': {
                'request_id': str(uuid.uuid4()),
                'timestamp': datetime.utcnow().isoformat()
            }
        }
        return JSONResponse(content=response_data)
    except HTTPException as he:
        logger.warning(f"Client error: {he.detail}")
        raise he
    except Exception as e:
        logger.error(f"Server error: {e}")
        raise HTTPException(status_code=500, detail="Internal Server Error")

@app.exception_handler(404)
async def not_found_handler(request: Request, exc: HTTPException):
    return JSONResponse(status_code=404, content={'error': 'Not Found'})

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")



客户端代码 (使用 asyncio 和 aiohttp)

import aiohttp
import asyncio
import json

async def fetch_data(url, method='GET', data=None):
    try:
        async with aiohttp.ClientSession() as session:
            if method == 'GET':
                async with session.get(url) as response:
                    if response.status == 200:
                        return await response.json()
                    else:
                        print(f"Failed to fetch data: {response.status}")
                        return None
            elif method == 'POST':
                async with session.post(url, json=data) as response:
                    if response.status == 200:
                        return await response.json()
                    else:
                        print(f"Failed to fetch data: {response.status}")
                        return None
    except aiohttp.ClientError as e:
        print(f"HTTP request failed: {e}")
        return None
    except json.JSONDecodeError as e:
        print(f"Failed to decode JSON: {e}")
        return None
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

if __name__ == '__main__':
    url_get_fastapi = 'http://127.0.0.1:8000/data?count=50'  # 对应 FastAPI GET 服务
    url_post_fastapi = 'http://127.0.0.1:8000/data'  # 对应 FastAPI POST 服务
    url_get_quart = 'http://127.0.0.1:5000/data?count=50'  # 对应 Quart GET 服务
    url_post_quart = 'http://127.0.0.1:5000/data'  # 对应 Quart POST 服务
    
    # FastAPI GET 请求
    data = asyncio.run(fetch_data(url_get_fastapi))
    if data:
        print("FastAPI GET response:")
        print(json.dumps(data, indent=4))
    else:
        print("Failed to fetch data with FastAPI GET.")

    # FastAPI POST 请求
    post_data = {"count": 50}
    data = asyncio.run(fetch_data(url_post_fastapi, method='POST', data=post_data))
    if data:
        print("FastAPI POST response:")
        print(json.dumps(data, indent=4))
    else:
        print("Failed to fetch data with FastAPI POST.")

    # Quart GET 请求
    data = asyncio.run(fetch_data(url_get_quart))
    if data:
        print("Quart GET response:")
        print(json.dumps(data, indent=4))
    else:
        print("Failed to fetch data with Quart GET.")

    # Quart POST 请求
    data = asyncio.run(fetch_data(url_post_quart, method='POST', data=post_data


总结

在本示例中,我们展示了如何使用 Quart 和 FastAPI 构建异步 Web 服务器,并通过客户端异步获取数据。这些代码示例涵盖了多种请求方式和数据处理方法,适用于高并发和异步处理的场景。

1. Quart (Flask 的异步版本) 服务器端

  • 请求处理:

    • 支持 GET 和 POST 请求。
    • 支持 application/json 和 application/x-www-form-urlencoded 内容类型。
    • 使用 Pydantic 进行数据验证。
  • 异步操作:

    • 通过 asyncio.gather 并行执行异步操作,例如模拟的数据库查询和外部 API 调用。
  • 错误处理:

    • 处理 404 错误并返回 JSON 格式的错误消息。
    • 捕获和记录服务器内部错误,返回 500 错误。

2. FastAPI 服务器端

  • 请求处理:
    • 支持 GET 和 POST 请求。
    • 对于 GET 请求,直接使用查询参数。
    • 对于 POST 请求,支持 application/json 和表单数据 (application/x-www-form-urlencoded)。
  • 异步操作:
    • 使用 asyncio.gather 并行执行异步操作,例如模拟的数据库查询和外部 API 调用。
  • 错误处理:
    - 捕获和处理 HTTP 异常,记录客户端和服务器错误。
    - 处理 404 错误并返回 JSON 格式的错误消息。

3. 客户端代码 (使用 aiohttp)

  • 功能:
    - 异步地发送 GET 和 POST 请求到服务器。
    - 支持处理 JSON 响应和错误。
  • 使用示例:
    - 演示如何分别请求 Quart 和 FastAPI 服务器。
    - 打印响应数据,帮助验证服务器端的功能。

应用场景

这些代码示例适用于需要异步处理和高并发的应用场景,例如:

  • 实时数据处理系统
  • 高并发的 API 服务
  • 需要与外部服务进行异步交互的应用

通过使用 Quart 和 FastAPI,我们可以有效地处理并发请求,提高应用的响应速度和处理能力。


补充

Pydantic 简介

pydantic 是一个数据验证和设置管理的 Python 库,提供了基于类型注解的数据验证功能。它主要用于定义和验证数据模型,确保数据符合预期的格式和约束。

主要组件
  • BaseModel:

    • BaseModel 是 pydantic 中的一个基类,用于定义数据模型。它允许你使用类型注解来定义数据字段,并提供自动验证和数据转换的功能。
  • conint:

    • conint 是 pydantic 提供的一个约束类型,用于限制整数值的范围。通过 conint,你可以定义一个整数字段,设置最小值和最大值约束。
示例代码

下面是一个简单的 pydantic 示例,展示了如何定义一个数据模型并验证数据:

from pydantic import BaseModel, conint, ValidationError

# 定义一个数据模型
class RequestModel(BaseModel):
    count: conint(ge=1, le=1000)  # count 字段必须是 1 到 1000 之间的整数

# 正确的数据示例
try:
    valid_data = RequestModel(count=50)
    print("Valid data:", valid_data)
except ValidationError as e:
    print("Validation error:", e)

# 错误的数据示例(超出范围)
try:
    invalid_data = RequestModel(count=1500)
except ValidationError as e:
    print("Validation error:", e)

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用C语言中的`qsort`函数和多线程来进行排序。`qsort`函数是C标准库中的一个排序函数,它可以对数组进行排序。多线程可以帮助提高排序的效率,特别是当需要排序的数组较大时。下面是一个示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> // 用于排序的比较函数 int compare(const void* a, const void* b) { return (*(int*)a - *(int*)b); } // 线程的排序函数 void* thread_sort(void* arg) { int* arr = (int*)arg; qsort(arr, 5, sizeof(int), compare); // 使用qsort进行排序,这里假设数组长度为5 return NULL; } int main() { int arr[] = {5, 3, 1, 4, 2}; pthread_t tid; // 创建线程并进行排序 pthread_create(&tid, NULL, thread_sort, arr); // 等待线程结束 pthread_join(tid, NULL); // 打印排序后的结果 for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); } return 0; } ``` 在上面的示例代码中,我们使用了`qsort`函数对数组进行排序,同时创建了一个线程来执行排序操作。在主线程中,我们使用`pthread_create`函数创建了一个新线程,并将数组作为参数传递给线程的排序函数。然后使用`pthread_join`函数等待线程结束。最后,我们打印排序后的结果。 请注意,上面的示例代码仅仅是一个简单的演示,实际应用中可能需要更复杂的逻辑和更多的线程来处理更大的数据。另外,要确保在使用多线程时正确地处理线程间的数据共享和同步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值