aiohttp(Python) vs PHP 异步请求 全方位对比

AI摘要
这是一篇【知识分享】性质的技术对比文章,系统梳理了PHP(Swoole/Workerman)与Python(aiohttp/asyncio)在异步编程上的核心差异。文章从底层事件循环、协程机制、语法写法(async/await vs 自动切换)、并发请求(gather vs Co::multi)、连接池复用、异常捕获到实际应用场景(FastAPI vs Swoole HttpServer)进行了全方位对照,并针对PHP开发者总结了5个常见Python异步坑点。内容专业、客观,属于正常的技术讨论与经验分享,无任何违规内容。

aiohttp(Python) vs PHP 异步请求 全方位对比

你有PHP开发底子,我先把两套语言的同步阻塞模型、异步底层原理、代码写法、坑点、使用场景一一对照,打通思维差异;
先梳理核心前提:PHP主流异步方案就2种:Swoole / Workerman,原生PHP完全没有异步。
Python:原生语言就内置 async/await 协程 + asyncio事件循环,aiohttp基于这套体系。

一、底层核心机制对比(最关键,弄懂就通透)

1)传统PHP(LNMP 普通php-fpm):完全同步阻塞

  1. 每来1个请求,php-fpm 开启一个进程处理;
  2. 调用curl请求第三方接口、网络IO、sleep等待时:整个进程卡住休眠,CPU无事可做
  3. 并发高了只能不断加进程,资源开销巨大;
  4. 无法实现单进程内并发发起多个HTTP请求。

2)PHP异步:Swoole/Workerman 协程(PHP唯一异步方案)

Swoole 提供:协程+事件循环,底层epoll多路复用,和Python asyncio设计思路几乎一模一样

  • 单进程依托事件循环,IO等待时让出CPU,去执行其他任务;
  • curl换成 Swoole\Coroutine\Http 协程客户端,就是PHP版aiohttp;

3)Python aiohttp + asyncio

Python 语言原生支持协程语法 async/await,asyncio是事件循环调度器
aiohttp = 基于asyncio事件循环的异步HTTP客户端
逻辑和Swoole协程1:1对标:
IO阻塞(等待接口返回)→ 交出控制权 → 事件循环调度其他协程运行

一句话对应关系

Python 概念 PHP Swoole 对应概念
async def 异步函数 function 协程函数
await yield/协程挂起(Swoole自动封装无需手动写)
asyncio 事件循环 Swoole EventLoop
aiohttp.ClientSession Swoole\Coroutine\Http\Client
asyncio.gather() Co::multi() 并发批量请求

二、基础语法对照:单次POST请求(调用Ollama接口)

版本1:PHP 同步 curl(最常用、阻塞)

<?php
$url = "http://127.0.0.1:11434/api/chat";
$postData = json_encode([
    "model" => "llama3:8b",
    "messages" => [["role"=>"user","content"=>"什么是RAG"]],
    "stream" => false
]);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);

// 阻塞:程序卡死在这里等待接口返回
$res = curl_exec($ch);
curl_close($ch);
$data = json_decode($res, true);
echo $data["message"]["content"];

特点:等待期间整个脚本停滞,不能干别的。

版本2:PHP Swoole 协程异步请求(非阻塞)

<?php
Co\run(function () {
    $cli = new Swoole\Coroutine\Http\Client('127.0.0.1', 11434);
    $cli->set(['timeout' => 30]);
    $postData = json_encode([
        "model" => "llama3:8b",
        "messages" => [["role"=>"user","content"=>"什么是RAG"]],
        "stream" => false
    ]);
    $cli->post("/api/chat", $postData, ["Content-Type" => "application/json"]);

    // IO等待时,CPU可以去执行其他协程,不会阻塞进程
    $result = json_decode($cli->body, true);
    var_dump($result["message"]["content"]);
});

版本3:Python aiohttp 等价写法

import aiohttp
import asyncio

async def request_llm():
    url = "http://127.0.0.1:11434/api/chat"
    payload = {
        "model": "llama3:8b",
        "messages": [{"role":"user","content":"什么是RAG"}],
        "stream": False
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=payload, timeout=aiohttp.ClientTimeout(total=30)) as resp:
            res = await resp.json()
            print(res["message"]["content"])

# 启动事件循环,运行协程函数
asyncio.run(request_llm())

三、核心关键字逐行对照(最难理解的 await、async)

  1. async def
    PHP:Swoole中普通函数放在 Co\run() 内部自动变成协程函数,不用标记关键字;
    Python:必须手动给函数加 async 标识,代表这是一个协程函数,普通代码无法直接调用。

  2. await
    作用:遇到网络IO,挂起当前协程,让出事件循环控制权

  • PHP Swoole:内置封装好了,调用协程Http客户端时自动挂起,不用写任何关键字;
  • Python:但凡IO操作(发请求、sleep、读文件)前面必须手写await,否则报错。
  1. async with
    PHP里没有异步上下文管理器概念;
    Python:异步资源(Session、链接)需要异步自动关闭,等价手动 close() 销毁客户端连接。

四、并发批量请求对比(最能体现异步优势)

需求:同时发起3个LLM提问,串行很慢,异步并发瞬间跑完

PHP Swoole 多协程并发

<?php
Co\run(function () {
    $prompts = [
        "什么是向量嵌入",
        "Chroma和FAISS区别",
        "Llama3部署难点"
    ];
    $tasks = [];
    foreach ($prompts as $p) {
        $tasks[] = Co::create(function () use ($p) {
            $cli = new Swoole\Coroutine\Http\Client('127.0.0.1', 11434);
            $cli->post("/api/chat", json_encode([
                "model"=>"llama3:8b",
                "messages"=>[["user", $p]]
            ]));
            return [$p, json_decode($cli->body, true)["message"]["content"]];
        });
    }
    // 等待所有协程全部执行完毕
    $results = Co::wait($tasks);
    var_dump($results);
});

Python asyncio.gather 并发(完全对等)

import aiohttp, asyncio

async def single_task(session, prompt):
    payload = {"model":"llama3:8b","messages":[{"role":"user","content":prompt}]}
    async with session.post("http://127.0.0.1:11434/api/chat", json=payload) as resp:
        data = await resp.json()
        return prompt, data["message"]["content"]

async def batch_request():
    prompts = ["什么是向量嵌入","Chroma和FAISS区别","Llama3部署难点"]
    async with aiohttp.ClientSession() as session:
        tasks = [single_task(session, p) for p in prompts]
        # 并发执行所有任务,收集结果 = Co::wait()
        results = await asyncio.gather(*tasks)
    return results

asyncio.run(batch_request())

五、连接池复用 对比(性能重点)

PHP Swoole

推荐全局实例化一个Http客户端连接池,复用TCP链接,避免反复创建销毁连接开销;

Python aiohttp

核心铁律:全局只创建1个 ClientSession 对象全程复用
千万不要每次请求都新建Session(和反复new HttpClient一个道理,损耗极大)
✅正确写法:全局会话

# 全局单例session
session: aiohttp.ClientSession | None = None

async def get_session():
    global session
    if session is None:
        session = aiohttp.ClientSession()
    return session

六、异常捕获对照

PHP Swoole 异常

try {
    $cli->post(...);
} catch (\Swoole\Coroutine\Http\Exception $e) {
    // 连接失败、超时
}

Python aiohttp 常用异常

from aiohttp import ClientConnectorError, ClientResponseError
try:
    async with session.post(...) as resp:
        resp.raise_for_status() # 非200抛出异常
except ClientConnectorError:
    print("服务未启动,连接失败")
except asyncio.TimeoutError:
    print("请求超时")
except Exception as e:
    print(e)

七、FastAPI + aiohttp ≈ PHP Swoole Http服务

这是你当下最贴合的场景:

  1. FastAPI:基于ASGI异步事件循环的Web框架
    等价:Swoole Http服务
  2. 接口内部使用 aiohttp 调用大模型接口
    等价:Swoole协程Http客户端
  3. 整条链路全程异步无阻塞,大量用户同时问答不会卡顿
    传统PHP-FPM做不到这点,这也是Python做AI后端碾压PHP的核心原因。

八、PHP开发者最容易踩的Python异步坑(逐个拆解)

坑1:同步函数里不能调用await/aiohttp

PHP:随便在哪都可以调用协程客户端;
Python:await 只能写在 async def 函数内部,普通def同步函数直接调用会报错卡死。

坑2:分不清同步requests 和异步aiohttp

requests = PHP curl(同步阻塞)
aiohttp = PHP Swoole协程客户端(异步非阻塞)
写RAG、LLM并发接口一律只用aiohttp。

坑3:频繁创建ClientSession

等同于PHP循环里不停new HttpClient,TCP频繁握手,性能暴跌。

坑4:忘记写await

Python调用异步方法不加await,拿到的只是协程对象,不会真正执行请求。

坑5:事件循环概念模糊

PHP开发者平时感知不到事件循环;
Python所有异步代码都跑在asyncio事件循环里,FastAPI内部自动维护事件循环,不用手动启动。

九、简明对照表汇总

功能 PHP(Swoole协程) Python(asyncio+aiohttp)
异步函数标记 无需标记 async def
IO挂起等待 自动协程切换 await 关键字
HTTP客户端 Swoole\Coroutine\Http\Client aiohttp.ClientSession
并发批量请求 Co::multi() / Co::wait() asyncio.gather()
超时设置 $cli->set([‘timeout’=>30]) ClientTimeout
上下文自动关闭 手动close() async with 自动释放
Web异步服务 Swoole HttpServer FastAPI

十、给你的学习建议

  1. 记住:Python异步 = Swoole协程,思维完全互通;
  2. 写对接Ollama的接口统一套路:
    FastAPI异步接口 → 全局复用aiohttp会话 → await发起请求 → 返回结果/流式输出
  3. 先熟练写单次请求 → 再练并发请求 → 最后封装通用LLM请求工具类。

需要我把你之前写的PHP调用大模型代码,逐行翻译成Python aiohttp版本给你对照看吗?

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!