ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

PHP与Go性能差距实测:框架、进程模型与选型

PHP与Go性能差距实测:框架、进程模型与选型 去年年底做过一次技术评审业务方的诉求很直接这个接口的 P99 已经摸到 800ms峰值一到就掉请求要不要把 Laravel 那套整体换成 Go。会上两种声音都有一种说 PHP 天生就慢早晚要换另一种说换语言也解决不了数据库的问题。我没在会上争回去花了两周把 PHP 各主流框架和 Go 侧常见框架在同一台机器上全跑了一遍又用 pprof 和采样器把热点逐个钉出来。这篇就把那两周的原始数据、对比口径和踩过的坑整理出来给正在纠结PHP 各框架和 Go 到底差多少的人一个可复现的参考。1. 先给结论差距不在语言在进程模型先把最容易误导人的数字摆出来。在同样的 8 核 16G 机器、同样的纯 JSON 返回端点上原生 PHP 脚本大概 11000 RPSLaravel 11 大概 1600 RPS而 Go 的标准库net/http裸写能跑到 78000 RPSgin 大概 62000 RPS。这一个切片里Laravel 和 gin 差了将近 40 倍。但把同一条 SQL 查询加进端点之后差距立刻收缩到 10 倍以内。如果再让 Go 侧走一层 RPC 去调 PHP 的遗留服务差距能压到 3 倍左右。这个收缩规律不是巧合它说明一件很关键的事PHP 与 Go 的差距大部分产生在每请求重建运行时这件事上而不是产生在语法翻译成机器码这件事上。1.1 三种 PHP 形态必须拆开谈很多对比文章把 PHP 当成一个东西这是最根本的方法论错误。实际生产里的 PHP 至少是三种完全不同的形态短生命周期形态mod_php或php-fpm。每个请求由进程池里的一个 worker 处理请求结束就回收几乎所有运行时状态。Laravel、Symfony、ThinkPHP 默认都跑在这个模式下。常驻内存形态Swoole、Webman、Laravel Octane、RoadRunner。进程启动一次框架 bootstrap 只做一次之后每个请求复用已经构建好的容器、路由表、配置。CLI 形态队列消费者、定时任务、数据处理脚本。这部分和 Web 性能基本无关但它决定了 PHP 在大数据量离线计算场景的表现也常常被拿来和 Go 的批处理做对比。这三种形态之间的差距比 PHP 和 Go 的差距还要大。同一个 Laravel 业务代码跑在 php-fpm 下 1600 RPS挂到 Octane 下能到 5200 RPS换成 Webman 甚至能到 7800 RPS。所以当有人问PHP 和 Go 性能差多少正确的反问是你说的是哪种 PHP1.2 越靠近 IO语言的影响就越小我习惯用一份分层归因的方式来看性能层级典型耗时占比Laravel MySQL换 Go 后能省掉多少进程/运行时启动20% - 35%几乎全部省掉框架 bootstrap容器、路由、中间件装配15% - 30%大部分省掉业务逻辑PHP 代码执行5% - 15%部分省掉JSON 序列化/反序列化5% - 10%部分省掉数据库/Redis 网络往返与等待30% - 60%一点都省不掉磁盘与日志写入3% - 10%少量省掉这张表是我在自己项目上采样后估的具体比例随项目差异很大但顺序基本稳定。它解释了一个非常常见的现象很多团队把接口从 PHP 重写成 GoQPS 涨了 8 倍但用户感知的 P99 只降了 30%因为瓶颈还在那条没走索引的 SQL 上。2. 压测环境怎么搭才不会被自己骗我必须坦白一件事第一轮测试的数据是错的。当时我得到的结果是Go 只比 Laravel 快 5 倍拿去准备写结论越看越不对劲最后发现问题出在压测工具本身。这节讲的都是血泪教训。2.1 让两边站在同一条起跑线上最容易犯的错是给 Go 侧配了 8 核给 PHP 侧只留了 2 个 php-fpm worker。php-fpm 的并发处理能力基本等于pm.max_children的数量默认值往往很小不改直接测等于人为给 PHP 戴了手铐。我的做法是准备一份标准化的容器编排PHP 侧nginxphp-fpmpmstaticpm.max_children328 核 × 4视单请求耗时调整memory_limit256M。Go 侧单进程GOMAXPROCS8GOMEMLIMIT4GiB。两侧共用同一台 MySQL 8.0 和 Redis 7.2避免缓存命中率不一致。压测机和被测机分离压测机配置必须明显高于被测机否则测的就是压测机的上限。关于 PHP 镜像有个很容易被忽略的点别用默认的php:8.3-fpm镜像直接上生产它没装 opcache 的推荐配置也没装pdo_mysql之类的扩展很多人在容器里测出一堆莫名其妙的慢其实是配置问题。而 Go 侧编译出来的静态二进制镜像通常只有 15-25MBPHP 侧加上扩展一般 150MB 起步这个差异在冷启动和弹性扩容时是实打实的成本。2.2 关键参数对照下面这张表是我固定使用的对照配置建议你第一次做对比时直接抄项目PHP 侧Go 侧并发模型pmstaticmax_children32GOMAXPROCS8内存限制memory_limit256MGOMEMLIMIT4GiBGOGC100字节码缓存OPcache 开启validate_timestamps0不适用JITopcache.jittracingjit_buffer_size64M不适用数据库连接每个 worker 一条长连接最多 32 条连接池MaxOpenConns50超时request_terminate_timeout30sReadTimeout5s/WriteTimeout10s网络接入nginx 反代 FastCGI直接ListenAndServePHP 侧的 opcache 配置我通常这么写opcache.enable1 opcache.memory_consumption256 opcache.max_accelerated_files20000 opcache.validate_timestamps0 opcache.interned_strings_buffer32 opcache.jittracing opcache.jit_buffer_size64M关于 JIT 我要泼一盆冷水PHP 8 的 JIT 对典型的 Web 请求提升很有限实测普遍在 5% 到 15% 之间因为 Web 请求的时间大头在启动、bootstrap 和 IO 上真正被 JIT 加速的密集数值循环占比很小。JIT 真正发光的地方是图像处理、加解密、数学计算这类 CPU 密集型脚本。如果你只是为了跑 Laravel 接口而开 JIT收益大概率对不起调试成本。另外开发机上千万别带着 Xdebug 测性能。xdebug.modedevelop会让执行速度直接掉一个数量级我见过有人拿带 Xdebug 的 PHP 去对比 Go然后得出PHP 慢 100 倍的结论。2.3 指标口径RPS 是给老板看的P99 是给自己看的压测工具我推荐wrk2或hey别用单线程的wrk。单线程wrk在 5 万 RPS 以上时压测机自己会先跑满一个核测出来的数字是被压测端和压测端共同决定的。wrk2 -t8 -c200 -d60s -R20000 --latency http://127.0.0.1:8080/json hey -z 60s -c 200 -q 0 http://127.0.0.1:8080/json重点关注四个指标而且必须一起看吞吐RPS反映整体处理能力但它可以被延迟换出来。P50 延迟体感基准线。P99 延迟真正决定用户投诉量的指标。错误率如果错误率不为 0前面三个都没意义。还有一件事要检查cgroup 的 CPU 限流。在容器里跑压测容器 CPU 被 cgroup 限流后表现的延迟曲线非常像框架性能差实际是内核在掐你。查一下/sys/fs/cgroup/cpu.stat里的nr_throttled。3. PHP 各框架的实测水位搞清口径之后正式跑数据。所有数据都是纯 JSON 返回和查一条主键记录两个端点各跑 60 秒取三轮中位数。3.1 框架启动开销一次请求里白干了多少活先看一个什么都不做的端点它最能暴露框架的固定开销。原生 PHP 脚本 11000 RPSLaravel 只有 1600 RPS中间凭空消失的 9400 RPS 去哪了我把这消失的部分拆成四块自动加载与类文件解析Composer 的 classmap 再快一个请求也要加载几百个类文件require的开销累加起来很可观。依赖注入容器装配Laravel 的服务容器在每次请求都要重新绑定、解析、实例化一批 service provider。这是最大的单块开销。路由匹配与中间件链构建路由表要先注册再匹配中间件链要按顺序组装成闭包洋葱。配置加载.env解析、config 文件合并。这四块加起来构成了框架税。而框架税在小请求上会显得特别夸张请求越轻框架税占比越高。这里有个和 Go 侧高度对照的现象——两边都在反射上付出代价。PHP 的 DI 容器靠反射读取构造函数参数类型来做自动注入Go 的encoding/json靠反射遍历结构体字段。前者拖慢启动后者拖慢序列化。理解这一点之后两边各自的优化方向就清楚了PHP 侧用缓存编译后的容器或切常驻内存Go 侧用代码生成替代反射。3.2 重量级与轻量级的真实分界线实测几款主流 PHP 框架的纯 JSON 端点框架版本纯 JSON (RPS)查一条记录 (RPS)单 worker RSS原生 PHP 脚本8.311000640022 MBLaravel11160090045 MBSymfony7140082042 MBThinkPHP82600140038 MBCodeIgniter42800150034 MBYii22.02100120040 MB规律很清楚按需加载做得越彻底、容器越轻、约定越少的框架纯 JSON 性能越好。CodeIgniter 和 ThinkPHP 领先不是因为代码写得更聪明而是因为它们要装配的东西少。Laravel 慢也不是实现质量差而是它给你塞的东西多——服务容器、事件系统、门面、队列、缓存抽象这些在生产项目里是真用得上的。所以我不建议拿这张表去评判哪个框架好。它只说明一件事如果你要做的是极简 API选型上确实可以挑轻量的如果你要做的是业务系统那么框架税是一次性付、长期受益的投资。3.3 常驻内存改写了游戏规则真正有意思的是常驻内存这一档。同样的 Laravel 业务代码不改一行换个运行方式运行方式纯 JSON (RPS)查一条记录 (RPS)说明Laravel php-fpm1600900基线Laravel Octane (Swoole)52002400容器与路由只构建一次Webman78003600原生 Swoole 协程框架极轻Hyperf65003200协程 注解功能更全看到没换运行时带来的提升3 到 5 倍比换语言的边际提升还要直观。而且它的代价远小于重写业务代码。但常驻内存不是免费的午餐它引入了全新的问题类别而且这些问题在上线半年后才集中爆发状态泄漏全局变量、静态属性、单例里缓存的请求数据会跨请求累积。最典型的是把容器单例和 Request 对象绑在一起内存曲线一路向上。连接管理数据库连接、Redis 连接变成常驻必须处理断线重连和连接失效。超时与异常隔离一个请求的致命错误可能拖垮整个 worker必须做完善的异常兜底。热更新改了代码要重启进程本地开发的反馈循环变长。这几条是我踩过最深的坑。如果你团队里没有人能看懂常驻内存下的内存曲线我建议先不要上性能提升不值得半夜被告警叫醒。3.4 部署形态的隐性差异顺便提一下部署。PHP 侧的标准形态是 nginx php-fpm源码直接放目录改完就生效。Go 侧是编译成单个静态二进制配合 systemd 或容器编排直接跑。这个差异在压测之外的地方价值更大Go 的单文件部署在灰度发布、回滚、多环境一致性上优势明显而 PHP 的改完即生效在快速迭代的业务场景里效率优势同样难以替代。这两件事都属于性能之外的工程成本但它们在选型里的权重往往被严重低估。4. Go 侧net/http 之上到底加了多少税接下来看 Go 侧。很多人默认 Go 框架开销可以忽略实测下来并不是这样而且各框架之间的差异比想象中大。4.1 标准库的基准水位net/http裸写一个 JSON 端点8 核机器上大概 78000 RPS。这个数字背后是 Go 运行时几个关键设计在起作用netpoller基于 epoll 的网络轮询器每个连接由 goroutine 处理但阻塞时不会被线程占用。goroutine 的轻量栈初始 2KB按需增长十万级并发连接的内存代价远低于线程模型。逃逸分析能在栈上分配的对象绝不丢到堆上直接减少 GC 压力。并发三色标记 GC绝大部分 GC 工作与业务逻辑并行STW 时间控制在亚毫秒级。这四条加起来就是省掉每请求重建之外的另一个大头Go 不是把 PHP 的重建成本优化了而是根本不需要重建。4.2 gin / echo / chi / fiber 的差异来自哪里框架纯 JSON (RPS)查一条记录 (RPS)路由实现备注net/http7800021000ServeMux基准gin6200019000压缩前缀树生态最全echo6400019500前缀树中间件风格类似 Laravelchi5500017500前缀树完全兼容 net/httpfiber9500024000基于 fasthttp不兼容 net/httpgo-zero4800017000前缀树 代码生成自带熔断限流缓存kratos4500016500前缀树全家桶B 站出品几个值得注意的点fiber 明显更快因为它建在 fasthttp 之上而 fasthttp 为了性能做了两件事复用请求/响应对象、绕过标准库的部分抽象。代价是不兼容net/http的中间件生态以及一个非常容易踩的坑——请求对象会被复用把ctx.Body()返回的字节切片存下来或丢给 goroutine 用下一次请求会把这块内存改写你会看到数据串号。我亲眼见过有人因为这个问题排查了两天。gin 与 net/http 之间约 20% 的差距主要来自路由匹配和Context对象池。gin 用sync.Pool复用 Context减少分配但它的c.JSON底层还是encoding/json反射开销一点没少。go-zero 和 kratos 的差距相对 gin 约 20% 到 25%来自它们自带的能力熔断、限流、链路追踪、日志、缓存适配。这些在真实项目里你迟早要自己写用它们相当于把成本提前了。4.3 结构体标签与反射Go 侧的框架税和 PHP 的容器反射完全对应Go 侧的反射开销集中在序列化。一个含 10 个字段的结构体encoding/json序列化时要做字段遍历、tag 解析、类型判断这部分开销在纯 JSON 端点里可能占到 30%。优化路径有三条代码生成easyjson、ffjson生成MarshalJSON方法绕过反射通常能带来 2 到 3 倍序列化提速。换用json-iterator接口兼容encoding/json改动成本低。设计上减少返回体这是最容易被忽视但收益最大的一条。返回 20 个字段的接口先问一句这 20 个字段有几个是真的被前端用了。对照 PHP 侧同样的思路是DI 容器用php artisan config:cache、route:cache预编译或者切到常驻内存直接消灭装配成本。5. 请求生命周期 vs 常驻进程差距的物理来源前面全是数字这节讲清楚数字背后的机制。想真正理解PHP 各框架和 Go 差在哪必须把一次请求在两个模型里的完整旅程对齐看一遍。5.1 一次请求在 php-fpm 里的完整旅程从 nginx 把 FastCGI 请求转给 php-fpm 开始调度fpm master 从空闲 worker 池里挑一个把请求交给它。初始化worker 从上次请求结束的状态开始重置超全局变量、重置输出缓冲、重置错误处理。编译/加载OPcache 命中则直接取字节码未命中才编译。这一步在 OPcache 配置良好的情况下很快。自动加载首次触发某个类时Composer 的 autoloader 去查 classmap 并require。框架引导实例化 Application、注册 service provider、加载 config、构建容器。路由与中间件匹配路由组装中间件洋葱。业务执行控制器调用、模型查询、视图渲染。响应与销毁输出、关闭连接、释放所有对象、GC 一轮。第 2 到第 5 步是每请求重建成本的物理来源。这四步在任何 PHP 短生命周期框架里都存在只是轻重不同。Laravel 重是因为它第 5 步干的事多原生脚本轻是因为它几乎没有第 5 步。5.2 Go 省掉的是什么Go 侧的一次请求接收netpoller 感知到新连接起一个 goroutine。路由匹配查一次前缀树通常几十纳秒。中间件链预先组装好的http.Handler嵌套调用。业务执行与 PHP 侧相同语义的代码。响应写入连接goroutine 回收或继续读下一个请求。对比一下就能看出Go 省掉的是 PHP 的第 2、3、4、5 步。不是优化是结构上不需要。这就是为什么Go 快 40 倍这类说法在纯 JSON 端点上成立——那个场景下 PHP 大部分时间花在重建上而重建这件事在 Go 里根本不存在。5.3 数据库连接数才是真正的隐形天花板这是一个我认为比语言选型重要十倍的问题。php-fpm 模型下每个 worker 通常各持一条数据库连接。max_children32就是 32 条常驻连接。如果你有 20 个 PHP 服务实例就是 640 条连接。MySQL 在连接数超过某个阈值后上下文切换和内存开销会让整体吞吐断崖式下跌。更麻烦的是连接无法共享worker A 闲着worker B 排队等连接你也没法把 A 的连接借给 B。压测时表现为CPU 没满、数据库没满但 RPS 上不去。Go 侧用sql.DB连接池可以精确控制上限并跨 goroutine 共享db.SetMaxOpenConns(50) db.SetMaxIdleConns(50) db.SetConnMaxLifetime(30 * time.Minute) db.SetConnMaxIdleTime(5 * time.Minute)同样的并发承载能力下Go 侧需要的连接数往往只有 PHP 侧的三分之一到一半。这意味着你的数据库可以少买几台或者同样的数据库能承载更高的业务量。这部分收益经常被算在语言性能里其实是连接模型的功劳。5.4 内存账本同样的 QPS 要花多少机器按后端 3000 RPS、P99 低于 100ms 的目标来算一笔账方案需要的实例数单实例内存总内存备注Laravel php-fpm4 台32 workers × 45MB ≈ 1.5GB6 GBP99 波动大Laravel Octane2 台4 workers × 60MB ≈ 240MB0.5 GBP99 稳定Webman2 台4 workers × 55MB ≈ 220MB0.45 GBP99 稳定gin1 台约 150MB压测中0.15 GB余量充足这张表的重点不是Go 省钱而是常驻内存的 PHP 已经能把内存效率做到和 Go 同一个量级。真正的差距出现在需要横向扩容到几十个实例的时候那时 PHP 侧连接数和内存的绝对值才会变成实际瓶颈。6. 拿数据说话用 pprof 和采样器把瓶颈钉死性能对比最容易犯的错是只看数字不下钻。数字告诉你差多少只有采样器才能告诉你差在哪。6.1 Go 侧 go tool pprof 的三步定位在服务里挂上 pprof 端点生产环境建议只监听 unix socket 或内网端口import _ net/http/pprof go func() { log.Println(http.ListenAndServe(127.0.0.1:6060, nil)) }()压测进行中抓 30 秒 CPU 采样go tool pprof -http:9090 http://127.0.0.1:6060/debug/pprof/profile?seconds30三步定位法看 top按 CPU 时间排前 10 个函数。如果encoding/json排第一说明是序列化瓶颈如果database/sql占比高是数据库等待如果runtime.mallocgc高是分配压力大。看火焰图能直观看到调用栈深处的累积开销比 top 更容易发现某层中间件在偷偷做序列化这类问题。看 allocsgo tool pprof -alloc_space找出分配最多的代码行。GC 高通常不是 GC 本身的问题是分配太频繁。顺便说一个实用技巧在压测前先跑一次 30 秒的 baseline把没有业务负载时的 CPU 曲线记下来。很多框架开销大的判断其实是被后台的定时任务、健康检查、日志刷新污染了。6.2 PHP 侧采样别用加法用采样器PHP 侧的microtime打点式统计会严重污染结果正确做法是用采样器。Tideways 或 XHProf 都可以tideways_xhprof_enable(TIDEWAYS_XHPROF_FLAGS_CPU | TIDEWAYS_XHPROF_FLAGS_MEMORY); // ... 业务代码执行 $data tideways_xhprof_disable(); file_put_contents(/tmp/prof_ . uniqid() . .xhprof, serialize($data));几个必须注意的点采样本身有开销通常在 5% 到 15% 之间别拿带采样的数据去和 Go 比。只在压测环境开生产上要严格控制采样率最好只对特定 header 的请求开启。看包含时间而不是自身时间。Laravel 里Illuminate\Foundation\Application::bootstrap的包含时间会非常高这是正常的要看它下面哪个具体 provider 最耗时。6.3 一个真实案例瓶颈从框架挪到了序列化我遇到的真实情况是这样的一个订单查询接口Laravel 侧 900 RPSP99 220ms。用 Go 重写后接口逻辑几乎照搬纯逻辑基准能到 18000 RPS。但上线后 P99 只从 220ms 降到 90ms远低于预期。打开 pprof 一看CPU 采样里encoding/json只占 4%database/sql相关占了 60% 以上火焰图显示大量时间在等一条 SQL 返回。去数据库看慢查询日志发现那条查询走的字段没有索引单次 70ms。换语言把 CPU 密集的部分几乎清零了但 IO 密集的部分一动不动。加完索引之后Go 侧 P99 直接降到 15ms而 Laravel 侧也从 220ms 降到 130ms。也就是说语言选型带来的收益是 130 → 15而索引带来的收益是 220 → 130。两者都重要但顺序搞反了会让人得出完全错误的结论。这个案例后来成了我团队的固定宣讲材料先做采样再做选型。7. 选型判断什么时候该留 PHP什么时候该上 Go数据说完了来谈决策。性能从来不是唯一变量但它是可以被量化的变量。7.1 用 QPS 和团队结构划线场景建议核心理由日活 5 万以内团队以 PHP 为主留 PHP做好 OPcache 与缓存性能不是瓶颈开发效率优先日活 5-50 万读写混合PHP-FPM 读写分离 队列削峰加机器比换语言便宜得多单接口峰值超过 5000 QPS考虑 Octane 或热点接口重写此时框架税占比明显网关、长连接、推送、IM上 Go常驻连接数万级时 PHP 很吃力需要极致单机 QPS 的无状态 APIGo gin单机 6 万 RPS 量级已有沉重 Laravel 业务渐进式先 Octane再抽热点推倒重来的风险远大于收益团队没有 Go 生产经验先别急观测、panic 恢复、连接池都要重建我个人的经验线是单接口峰值持续超过 3000 QPS就该认真评估常驻内存方案超过 8000 QPS才值得为这个接口单独引入 Go。低于这个量级把索引、缓存、N1 查询、慢日志这些基础工作做好收益通常更大且即时。7.2 混合架构的落地方式现在我最推荐的形态是混合Go 做接入层和热点PHP 做业务层和后台。Go 侧BFF/网关、鉴权、限流熔断、协议转换、SSE/WebSocket 长连接、文件上传下载。PHP 侧订单、结算、营销规则、运营后台、定时任务、报表。通信方式内部用 gRPC 定义契约或者简单点用 HTTP JSON。别一上来就上 gRPC存在多语言团队时它的维护成本不低。这么分的好处是两边各用所长。Go 扛住入口的并发PHP 保留业务迭代速度。而且这个架构允许你按接口逐个迁移风险可控。7.3 迁移期的共存与灰发迁移期的几个实操要点先双写日志再切流量。让 Go 和 PHP 同时接收请求只返回 PHP 结果比对两边输出是否一致。跑够一周再切。按 header 或用户 ID 灰度。切到 Go 的用户如果出错能立刻回退到 PHP。数据库连接数要预留。迁移期两套服务同时在跑MySQL 的连接数会翻倍提前把max_connections调高并监控。注意时区、序列化格式、空值处理这三个高发差异点。PHP 的json_encode对空数组和空对象的处理和 Go 的omitempty行为不一样前端会直接报错这类问题在灰度期一定会遇到。8. 几条反常识的经验最后分享几条和直觉相反、但我在实际项目里反复验证过的经验。第一框架越重常驻内存的收益越大。看起来轻量框架跑常驻内存应该更划算实际相反。因为 Laravel 的框架税本来就重把它消灭掉带来的相对提升更明显。原生 PHP 脚本切常驻内存反而收益有限因为它本来就没有多少可省。第二P99 比 RPS 更能决定你要不要换技术栈。很多团队的 RPS 曲线看着健康P99 却已经爆了。原因通常是 php-fpm worker 排队——请求在 fpm 的 backlog 里等这段时间不计入 PHP 执行时间但用户能感知。查 fpm 的listen_queue和max listen queue指标比看 RPS 有用得多。第三别把 JIT 当性能救命稻草。它解决的是 CPU 密集脚本的问题不是 Web 请求的问题。你在 Laravel 里开 JIT得到的提升可能还不如打开config:cache和route:cache来得明显。第四Go 的并发优势需要正确的代码才能兑现。我见过把 Go 写出纯串行逻辑的代码——所有请求共用一个锁MaxOpenConns1结果性能还不如 PHP-FPM。Go 给你的是可能性不是保证。第五压测数据永远只能当参考。我上面所有数字都来自一台特定配置的机器换一台硬件、换一个内核版本、换一个 MySQL 版本数字都会变。你要相信的是趋势和归因方法不是具体数值。真正值得抄走的是那套流程固定环境、标准化配置、采样下钻、分层归因。最后一条也是最重要的一条在决定换技术栈之前先花两天把慢查询日志、pprof 火焰图和 Tideways 采样报告都看一遍。我经手的性能优化里真正需要换语言才能解决的占比不到两成。剩下八成都是被PHP 就是慢这个印象挡住了视线。
返回列表