当前位置:首页>南京>南京大学操作系统原理# 21 — 一个 Token 的旅程

南京大学操作系统原理# 21 — 一个 Token 的旅程

  • 2026-06-23 03:24:48
南京大学操作系统原理# 21 — 一个 Token 的旅程

并发编程总结

不知不觉,课程已经进行到后半部分了。大家应该已经感受到 Malloc 实验的"恶意"——要真正写一个并发程序,哪怕只是一个 Malloc/free,也只是复杂系统中一个非常小的底层部分,但只要里面有一点点错误,都是致命的。

所以你们现在应该对整个系统设计者们产生敬畏:这件事绝不容易,你需要一整套方法和工具。正如我讲过的各种 sanitizer、deadlock detector,它们都是在实践中发现"没有这样的工具兜底,人类本身也很难做好"之后才出现的——就像今天要做的 Harnessed Engineering 一样。

今天我就对所有并发部分做一个总结。虽然很想做成一个 hacking day,但今天代码准备得比较仓促,我会尝试把过去五周的并发内容串联起来。


数据中心与并发编程:Token 的旅程

今天的主题是"数据中心与并发编程",我选的例子叫一个 Token 的旅程:假设我现在和某个大语言模型对话,收到了一个 token,在这个过程中大概发生了什么?我会讲得很概要,帮大家把前面学过的各种知识串联起来。

先回顾一下并发编程里我们学了什么。我们学了多处理器编程——从入门到放弃。入门的时候,我们用 spawn API 打开了一个"魔鬼的盒子":你能 spawn、能 join,理论上就可以实现任何计算图。

你可以放一个线程出去,当然还是需要和其他线程同步,所以有互斥锁、条件变量、信号量这样的机制。有了计算图,理论上就可以并行化任何程序。我们甚至还有一个实验——gpt2.c——去找热点然后做线程并行化,大家可以早点开始;虽然 Malloc 应该是整个实验体系里最难的,但并发编程才是你们对 system 设计者们产生敬畏的真正来源。


轻量级协程与非阻塞 IO

如果对线程的 spawn/join 模型不满意,还可以有更轻量级的选择,比如协程(coroutine)。结合非阻塞 IO 和 goroutine,既可以像协程一样轻量级地切换,又能在多处理器上并行执行,非常适合实现后端业务代码。

JavaScript 里的 Promise、async/await 本质上也是在描述一个计算图。你可以把所有并发编程模型都理解成某种形式的 spawn/join,只是"如何并行"不再由你的编程语言决定,而是由整个运行框架来调度。

上节课讲了一个有意思的故事:我们的 CPU 内部其实是并行的。虽然看起来是顺序地执行 1、2、3、4、5 这样的指令,但 CPU 内部有乱序执行(out-of-order execution)机制。这是从 1990 年代到 2000 年代初为了维持摩尔定律非常关键的技术,但到大约 2005—2006 年开始失效,因为继续提升单处理器性能的收益越来越小,必须转向一个新的方向。


SIMD 与 CUDA 线程模型及高性能并行计算

在芯片上放更多的处理器,才能把能效比救回来,维持摩尔定律。如果想极致最大化计算密度和能效比,那么处理器里译码部件消耗的能量最好能降到零。

为此出现了两种技术。第一是 SIMD(单指令多数据):一条指令可以操纵一个 512 bit 的大型数据,并把它分成多个小块同时处理。第二是 CUDA 的 SIMT(单指令多线程)编程模型:有很多套 ALU 执行单元和寄存器,但共享一个 program counter。

同一个 warp 里所有线程执行完全相同的指令。即便有分支(如 if a else b),也会顺序地执行两个分支,但在执行某个分支时,只把条件激活的那些线程打开,其他线程相当于什么都不做。

CUDA 实现高性能的方式是:每个线程有自己独立的寄存器,其中存有线程 ID(例如 threadIdx.xthreadIdx.y)。线程根据自己的 ID 算出数组下标,于是接下来一条 store 指令从整个 warp 来看就是对一段连续内存的写入,可以在内存控制器上发出 burst 的读写,速度非常快。这就是 SIMT 这个聪明的模型。当然今天还会讲:如果你觉得这样还不够高效,怎样再压榨最后一点性能。


真实系统性能与 DeepSeek API 实践

作为并发部分最后一节课,让我们来看看真实系统里到底发生了什么。还是从大家最熟悉的用户视角开始。

这是来自 DeepSeek API 官方网站的数据。我选 DeepSeek,第一是够便宜,第二也挺好用。它会告诉你:只要在环境变量里做如下配置——环境变量又是操作系统课的内容,大家还记得吗?期中考试考过的。


execve 环境变量继承机制

execve 有一个参数叫 envp,它会在进程加载时放到栈上的某个位置,并在子进程之间继承——这是一个非常重要的特性,使得你在 shell 里设置一个环境变量之后,它会不断向下传递给所有子进程。

这就意味着:即便是在子进程里执行一个 curl,也能收到 DeepSeek 的 API key。然后我会把这样的请求发给 api.deepseek.com;DeepSeek 还有一个与 Anthropic API 兼容的接口,你甚至可以在 Claude Code 里切换到 DeepSeek 来使用。


JSON 数据与 HTTP 响应调用模式

你给它的是一段 JSON 数据,执行后可以收到一个 HTTP response,看到 chat 补全的结果。这种调用模式在计算机使用过程中可以说无处不在。

比如你们的 make submit,有没有好奇过它背后是怎么工作的?你甚至可以让 AI 去读这段代码,AI 会告诉你:最终我们用 curl 从服务器上下载一个脚本,然后通过管道传给 shell 执行。


脚本分发与安装机制

如果我想关掉 make submit,一方面可以在后台拒绝请求,另一方面也可以直接在服务器上把那个脚本文件改掉。同学们刚开学时看到的那个 "Not Open" 提示,就是这样实现的。

你们会发现很多软件都用这种方式安装——比如 Homebrew 的安装页面就让你把一行命令粘贴到终端里,下载脚本再执行。类似地,我们也准备了一个 Python 程序,使用 requests 库,准备一个 data,调用 DeepSeek 的某个模型,让它返回一个 chat completion。


命令行聊天与管道输入

你随时都可以让 AI 帮你实现一个命令行聊天工具,不再需要打开网页。命令行聊天的好处是可以用管道把各种输入送给它。

作为计算机科学专业的同学,我希望大家学完操作系统课之后还能多一点探索精神。我执行了一个 chat.py,执行完就结束了——但操作系统课告诉你,你永远可以把任何程序"打开"来看看里面到底发生了什么。


程序执行与网络课介绍

大家正好在上网络课。网络课的核心 takeaway 是:你的本地数据是怎样到达地球另一端的服务器的?中间发生了什么?你们会学 TCP 拥塞控制、BGP 路由等重要机制。

而在操作系统课上,我选择从另一个角度切入——用工具来观察这整个过程。


使用 strace 追踪系统调用分析

我们在操作系统课上介绍过一个工具:strace。它可以直接追踪系统调用,还可以专门分析与网络相关的系统调用。

让 AI 先看一下这个程序在干什么,然后真正去做 strace。(运行时有可能会把 API key 泄露出来,因为 strace 会记录所有文本传输,所以这里就不展示了。)AI 很快读完了 strace 的 log,得到了一份非常精简的摘要。

这里面所有的操作,都可以和你们在网络课上学到的内容完全联动——计算机科学各门课之间是紧密绑定在一起的。


网络流程与 DNS/TCP 连接分析

AI 给出了一个流程:第一幕是 DNS 解析。不知道你们网络课有没有考 DNS 用的是哪个端口——是 53。如果你反复观察这些程序的执行,你就会对这些细节留下印象;即便在考试中未必第一时间想到 53,但如果是选择题,你一定见过这个数字。

接下来 strace 会显示 TCP 连接的建立过程。比较重要的系统调用是 connect,它连接到目标 IP 地址的 443 端口(HTTPS),然后进行 TCP 三次握手。

你还可以做得更多:把域名解析的过程展开来看。通过在本机运行更多命令,就可以把网络课的知识和实际系统的行为联系起来。


DNS 解析:大型服务的多 IP 与 CDN 架构

比如对于 api.deepseek.com,如果你查它的 IP,会发现它有不止一个——因为这是一个大型服务提供商,使用了分布式 DNS。你会看到两个 IP 都可以用:58.49.197.113218.92.146.107

而且在地球另一端执行同样的命令,很可能会看到不同的 IP。一个真正面向全球用户的严肃网站,其 DNS 设计比你想象的要复杂得多。还有工具能告诉你这是腾讯云的 CDN 域名——也就是说这个 API 请求并非直连 DeepSeek 源站,而是走了 CDN。


从 Traceroute 到 AI 网关:请求链路的逐层追踪

如果你想知道包是怎样到达另一端的,可以用 traceroute——这是网络课上也学过的工具。traceroute 的原理是逐步增大 TTL(time-to-live)的值,每次多走一跳,从而探查整条链路上经过的路由器。你们网络课上应该展示过这个内容,这样就把两门课联系起来了。

我们的请求终究会到达数据中心的另一台计算机。那台计算机大概率是一个负载均衡器(load balancer),而不是真正提供服务的机器——它把请求转发给若干 worker(比如 16 或 32 个),转发的代价远小于处理的代价,通过这种层层转发就能扛住非常大的负载。

比如访问 api.deepseek.com 会收到 401(因为没有合法的 key),同时 HTTP response header 里的 Server 字段是 openresty,这很可能还是另一个 API 网关。而访问 deepseek.com,server 显示的是 Cloudflare——又是一个代理,它甚至还拒绝了我的 curl 访问,因为 User-Agent 字段不匹配。

慢慢和 AI 对话,你就可以了解这些应用层协议里发生了什么。但从操作系统的角度来看,这一切都是由几个系统调用实现的:sendrecvconnect,或者对文件描述符的 read——你看到的就是文本形式的数据。在网络链路的每一层,数据都会被加上头和尾("交网络税"),但应用程序收到的还是那段文本。

业务节点收到请求之后,其中包含了 header 里的 API key(从环境变量里读出来的)和 body 里的 JSON 数据。到这里已经很复杂了,但真正麻烦的事情才刚刚开始。

你以为向 DeepSeek 请求只是"给我一个 JSON,你去算一个 token 回来"?在以前的 Web 1.0 时代或社交网络时代,HTTP 后端基本就是查数据库——无论淘宝、QQ 还是微信,到达后端要么查聊天记录,要么取图片(图片早已在 CDN 上分发好了,根据 URL 里的 hash 就能取走)。但对于大语言模型来说,后端要干的事情远不止这些:需要 Authorization(判断 API key 是否合法)、计费、审计……你们经常看到在 DeepSeek 里问了一个敏感问题,它开始输出,然后输出突然消失——这些都是后端在做的事情。

我们学过的操作系统 API 和并发编程这些知识,默默支撑了你们看到的这一切。把我们做过的所有实验拼起来,你就得到了一个相对完整的计算机科学 big picture。


一个实验撑起一个网站

刚刚发布的那个实验是 httpd——你们要实现一个真正的 HTTP 后端,还要支持 CGI。在 BBS 时代,你们的实验作业就可以真正撑起一个网站,甚至可以是一个足够好的、能挣钱的 startup 产品。虽然在今天,AI 一秒钟就可以帮你把这个问题解决掉。

今天就分成两个部分来讲数据中心里到底发生了什么:一是数据中心里的并发编程,二是从 Token 到 Tensor——你的一个 token 到底是怎么产生的。


数据中心并发编程视角

说到数据中心:全世界的人都可能访问同一个 API(api.deepseek.com),这些请求都在数据中心里处理。数据中心是一个"网络化的计算与存储资源集合,可以交付共享的应用程序和数据"(a network of computing and storage resources that can enable/deliver shared applications and data)。

数据中心的发展分上下两个半场。上半场是从 1990 年代的静态 Yahoo 式页面,到 Facebook、微信、淘宝,再到移动互联网,规模不断增长,所有数据都在云端——云端有你完整的数字人格(personality),你的手机和电脑消息完全同步。


数据隐私与 AI 推理算力

云端有完整的数字人格,同时也意味着我们实际上没有任何隐私。理论上,腾讯有你所有 QQ 和微信的聊天记录,知道你是什么样的人。只是法律不允许他用这些信息做某些事情——但有些事情是法律授权下允许做的,比如涉及刑事案件时,即便双方本地都删了聊天记录,服务器端依然可以恢复。

下半场是从 2022 年至今的 AI 推理时代。以 DeepSeek V3 为例:Flash 版本有约 2840 亿(284B)参数,但每次激活的是约 130 亿(13B);Pro 版是 1.6T 参数,每次激活约 490 亿。这只是每个 token 的计算量,还不包括计算 KV Cache 的成本——这个我们一会再说。

大家应该在 DeepSeek 发布时看到那行红色小字,说等升腾 950 的计算节点上线以后还会再降价一次。虽然现在价格已经很便宜,但有了新算力之后还可以更便宜。


AI 降价与数据中心产业链

这就意味着,数据中心其实是一个产业链。当你要服务全世界人民的应用时,就需要建数据中心:需要土地、水、电、人员、保洁……这是一个非常复杂的问题,每个人都不可能了解所有细节。

我们在学校里很有意思——大家都在做题,但很少讲这些题目是怎么来的。实际上,操作系统的发展是和产业结构、市场环境紧密相关的。操作系统本身固然重要,但真正驱动它发展的,是背后的市场供需关系。


就业市场供需与职业焦虑

你们都很在意毕业能不能找到工作、薪资怎么样,听到的永远是某某又拿了让人无法拒绝的年薪,然后就想"如果我也能有那个年薪就好了"。你们每天刷公众号,制造各种焦虑。

这焦虑的背后,其实是你们不太知道一个课堂上不太教的"世界模型"——因为课堂更多关注技术,而技术总有一天会过时。所有的技术都和产业结构、市场环境息息相关。


时代变迁下的个人成长与数据中心技术

你们这些"做题家"进入社会以后还会经历一次重新学习。比如,一个数据中心公司的本质是什么、供应链是什么、什么是股权……这些"世界模型"的知识,课堂上几乎不教。

所以你们在课堂上真正应该学到的,是"当我讲一个技术的时候,它是在什么历史时间点被需要的,它是怎么被设计出来的,而你有没有能力设计出这样的技术,并且看到未来会发生什么"。你们每个人都该想一想:等到你们毕业的时候,世界会发生什么样的变化,你应该成为什么样的人,才能适应这些变化。

我觉得所有这一切都指向同一个回答:你们每一个人都必须成为一个超级个体。如果你不是,在毕业的那一刻可能就被淘汰了——因为我们在不断感受到"也许有一天 AI Agent 真的会取代某些工程师"的压力,这是你们需要认真思考的事情。


CRUD 工程师被 AI 取代:小数据增删改查场景

大语言模型火起来之前,已经有很多应用在做和调用 api.deepseek.com 相似的事情——处理大量实时的小数据增删改查(CRUD)。所以 CRUD 工程师已经被 AI 彻底取代了。

这些小数据处理包括:淘宝下单(把订单写进数据库)、发帖(把帖子写进数据库)、查聊天记录(从数据库取出来)。以 DeepSeek 为例,还包括:验证 API key 是否合法、弹幕的时间戳记录、计费(这次 API call 收多少钱)、判断缓存是否命中、应该用哪种 pricing……各种各样相对比较小的处理。


DeepSeek 网页聊天记录与追问功能

DeepSeek 本身还有一个完整的网页界面(deepseek.com),和 API 后端不完全一样。那个网页会保存你所有完整的聊天记录,今天聊完,明天还可以回来继续追问。这些都是传统数据中心里海量分布式数据处理要干的经典事情。


数据处理的多层次应用

除了实时增删改查,数据中心里还有很多其他类型的数据处理。比如半离线的周期性记账:前面说过,哪怕实现一个可扩展的 sum++ 都很困难,分布式记账可能有延迟,精确账单(日账单、月账单)需要单独的半离线数据处理。

还有备份、数据看板,以及离线的大规模数据处理——包括神经网络训练(每轮训练动辄几百万美元),以及内容索引。分布式数据处理的诞生,正是因为 Google 当年能用分布式机器把整个互联网存下来,然后还需要运行程序把它变成可搜索的索引。

现在我发现自己用搜索越来越少了,因为大语言模型可以直接帮我解决更复杂的问题。


搜索与 AI 带来的生产力跃迁

但在大约十年以前,你学会 Google 搜索,你和别人就有十倍的生产力差距。今天你会用生成式 AI,你跟别人就有一百倍乃至一千倍的生产力差距——就是这么来的。

所有应用——Google、Meta、通义千问、DeepSeek——无一例外,都在数据中心里面临一个 1999 年由 Dan Kegel 提出的 C10K 问题(万并发问题)。


C10K 问题与高并发架构演进

C10K 问题是说:如何让一台 web server 同时服务 10,000 个并发客户端?1999 年时,应用规模已经增长到可能有一万个客户端同时访问,服务器在计算上多少能扛住,但如果软件写得不好——比如每个请求都 pthread_create 一个线程——就没法支撑这个并发量。

这样的问题催生了很多操作系统层面的进步,包括 epoll。在 epoll 之前有 select,两者功能差不多,都是监听多个文件描述符、有数据才继续处理,但 select 的 API 设计并不是为 C10K 准备的,在这个规模下有严重的性能问题。

这催生了一系列技术:nginx 这种事件驱动架构,以及 goroutine 这样的并发模型,都是在这个历史背景下产生的。等到 C10K 解决之后,大家很快发现:能服务 1 万个客户端,就能服务 1 亿个——于是又出现了 C10M(千万并发)问题。

摩尔定律以 18 个月为周期缓慢增长,如果要从 10K 突然跳到 10M,而且还有各种负载要求,事情就完全变了。光靠协程或异步事件编程已经不够,因为数据中心对产品体验的要求是真正高吞吐、低延迟的事件处理。


增删改查的复杂性

增删改查这个问题比你们想象的要困难。处理一个事件——比如在淘宝下一个单——不仅仅是一个业务系统内的事情:淘宝会涉及支付宝,支付宝还会涉及银行,可能有一千多个模块被拉起来。你依然要保证整个系统的性能,这非常有挑战。

很多程序的性能问题到至今都没有完全解决,比如微信小程序的体验就明显不如原生 App。


App 与小程序的网络容错体验差异

使用原生 App 时,对网络延迟或故障的容忍度会好很多;但如果是微信小程序,体验就相对要差很多。

举个例子:你们觉得 Malloc 实验已经很痛苦了,可如果在实际系统中用一把"大锁保平安",会导致什么问题呢?比如一个并发哈希表,已经有几十 MB 大了。


Hash Table Resize 延迟问题

这时候要对哈希表 resize:需要重新 allocate 一块几十 MB 的内存,做一次 memory copy(甚至比 memory copy 代价还高),拷贝完再把旧的释放掉,完成整个迁移。

如果这次内存迁移花了 100 毫秒,那么在这 100 毫秒里,所有几万甚至十几万个并发客户端都要等待。这对 P99 延迟就是毁灭性的伤害。

有一个著名的研究结论:每当延迟增加 100 毫秒,用户就会成倍流失——因为你让他觉得你的服务"比较卡"。


响应速度与服务质量

用户希望按下一个键就立即有返回;如果感觉慢,就会认为你的服务做得不好。而在海量请求涌入时,任何系统都可能扛不住。

比如前两年,雷军在小米汽车发布会上展示小爱同学的功能——


小爱同学被电视唤醒引发集体响应

雷军在发布会上叫出"小爱同学",而关注小米汽车的人大多是米粉,家里至少有一台小米设备。有些人在电视上看直播,电视里喊出"小爱同学"也会唤醒他们的小爱音箱。

于是全国的小爱音箱同时被唤醒,形成了一种类似 DoS(拒绝服务攻击)的效果——海量请求瞬间涌入数据中心,服务完全无法应对,导致全国小爱音箱在发布会期间集体瘫痪。我们想要解决的就是这样的问题。


分布式系统弹性与 CAP 原则

数据中心并发编程真正想解决的,不是"无论有多少客户端都能扛住",而是:在一个很大的弹性范围内,用户突然增长时系统能接住,峰值过去后系统又可以把资源还出来。

并且,真正麻烦的是你还需要保证超高的可靠性——没有人允许 QQ 和微信的聊天记录丢失。这就是分布式系统里你会遇到的最大难题。

就像有"功耗墙"、"内存墙"这些瓶颈,分布式系统里还有一个更糟糕的"不可能定理"——CAP 定理(CAP Theorem):在一个分布式系统里,Consistency(一致性)Availability(可用性) 和 Partition Tolerance(分区容忍性) 三者不可兼得。

Availability 很容易理解:你给我一个请求,我最好立即返回,不能无限延迟。Partition Tolerance 也好理解:不同地域的数据中心(比如南京、北京、杭州)之间有物理线缆相连,但没有人能保证那根线不会被施工挖断或出现网络延迟。Consistency 的意思是:不管在哪个地方做操作,所有人看到的结果都像是一个全局有序的序列——先做 1、再做 2、再做 3。


CAP 不可能三角的通俗解释

举一个例子你们就能理解为什么 CAP 三者不可兼得。

假设你现在想发一条朋友圈,不想让你妈看到,于是你先把你妈屏蔽。作为计算机科学专业的同学,你应该意识到:所谓的"屏蔽",背后其实就是一个 HTTPS 请求——向某个 api.wechat.com 发送一个增删改查操作,把你妈和你之间的朋友圈可见性数据删掉。然后你再发朋友圈,你认为这两件事在手机上是有先后关系的:先等屏蔽请求返回,再发朋友圈。

但问题来了:如果要保证 Consistency,系统就应该等到屏蔽操作在整个全域数据中心都同步完成后,再给你返回——但延迟太大了。所以实际上,系统为了 Availability,会先告诉你"已经屏蔽了",然后在后台悄悄同步。

然后可能发生的是:你在学校校园网上发起了屏蔽请求,屏蔽完成后你切换到了 5G 网络,在 5G 网络上发出的朋友圈可能被路由到了另一个数据中心(比如杭州)。

这时问题来了:假设你妈手上有两部手机,一部在南京、一部在杭州,同时在刷朋友圈。你的屏蔽请求先进了南京的服务器,它会慢慢通知杭州的服务器;但如果杭州那部手机在通知到达之前刷新,你妈就会在杭州的设备上看到你的朋友圈——虽然你已经先屏蔽了她。这就是因为有两个数据中心,它们之间存在延迟。

如果你要容忍 Partition Tolerance(网络可能分区),又要保证 Availability(请求立即返回),那就永远无法保证 Consistency——两个数据中心对同一个共享数据结构的操作,在全局上必然无法实时一致。

三者的取舍简单来说:要 Consistency + Availability,那就是单机,假设它永远可信;要 Availability + Partition Tolerance,做超大规模分布式系统,就必须一定程度上牺牲 Consistency;要 Consistency + Partition Tolerance,就可能需要让某些请求阻塞等待,牺牲部分 Availability。

实际上,系统设计者们花了大约十年,从 Google 最早的那几个分布式系统开始,做到了今天你完全感受不到 CAP 的存在——你感觉微信的数据非常安全,从来不会丢,服务也非常稳定,几乎没有明显延迟。CAP 依然存在,但他们用了很多办法让你感受到好的体验。


API 计费与 Dashboard 延迟问题

DeepSeek 的 API key 也有类似的 CAP 问题,因为需要用 key 做 Authentication,还要计费。你到 Dashboard 里看到花了多少 token、多少钱,但那个计费数据是有延迟的——你的 API 请求已经返回了,但刷新 Dashboard 可能要等几秒钟或一分钟才能看到更新。


拉黑 API 与 CAP 理论:数据中心业务的类比

这不就是刚才说的"屏蔽再发朋友圈"的例子吗?你要请求大语言模型推理的 API,同时又可以随时把 API key 下线,就会撞上 CAP 定理。

这样一个业务系统在数据中心的意义上涉及非常多的东西:一台机器上可能有很多个 worker,这些 worker 共享内存;机器和机器之间通过网络连接;网络还可能涉及跨数据中心的通信。


分布式并发:比无锁队列更复杂的噩梦

你们写 lock-free 数据结构的时候已经够痛苦了。但如果你要写一个程序,它不仅有共享内存,还有网络,而且随时随地都有机器可能 crash 或网络可能 delay——分布式系统最糟糕的就是这一点:一台机器从机架上断开,可能是电源断了,可能是网线断了,在拥有大量机器时这些都是不可避免的。

你可以这样想:你的并发模型变成了——不仅不知道其他线程什么时候会访问共享内存,而且这些"线程"随时随地都可能在执行到任何一个时刻时突然消失——你依然要保证系统能正常运转。可想而知有多难。


分布式系统的编程抽象与思维转变

为了在这样的数据中心上编程,其实是在重走 UNIX 走过的路线:每当一个新的需求出现,你需要的是构建一个全新的、好用的编程抽象。UNIX 赢,赢在它的编程抽象——管道、组合、fork 这样的机制。

对于单机的多处理器系统,openreadwrite 已经工作得非常好了。但对于分布式应用,如果还是让程序员去写 openreadwrite,把容错这些极其难做的事情全部交给用户,那是行不通的。

所以在做分布式系统时,有一个核心的 mindset change(思维转变):UNIX 的模型是把数据带到程序;而在分布式计算中,程序随时都可能消失,这时候需要的是把计算带到数据,而不是把数据带到计算


分布式计算的核心:把计算带到数据

一旦想通了这一点,你就会发现分布式系统的设计其实没有那么困难。Google 就是干了这件事——从 Google File System、Bigtable 到 MapReduce,建立了它的帝国,本质上就是这个思路的体现。

UNIX 时代"Everything is a file"的哲学,在分布式计算时代依然成立。Google 只需要做好一个文件系统的抽象——Google File System:把文件切片存到不同机器上,可以存储比任何单机都大得多的数据(比如 1 PB),但这些机器对你完全透明——你编程时看不到机器,只看到文件。

你对文件做操作,操作完写到另一个文件。你依然有 Program、有复杂的算法,但这个 Program 不再是"我把数据塞进来然后运行",而是以文件为中心——把计算推到数据所在的地方。在文件系统的基础上再构建 Key-Value 数据库,就可以解决增删改查的问题:用 Key-Value Database 就能做 API key 的校验和删除。


分布式计算与数据库解决 C10M 问题

有了 Database,C10M 的问题在一定程度上就解决了——只需要查询这个 Database。它的背后是分布在很多数据中心的分布式数据库,读取很快,写入也相对高效。

此外他们还为超大文件上的批量计算开发了 MapReduce——这三篇论文(Google File System、Bigtable、MapReduce)开启了分布式计算的新时代,解决了分布式计算里的编程问题。它把实现细节留给分布式系统层,每台机器上依然是 Linux,但对外暴露的接口不再是 Linux 底层的 openreadwrite


计算图编程抽象

那么今天,我们怎样为复杂的分布式系统编程呢?还是回到前面说的:所有并发编程的任务本质上都是计算图。

所以最好的编程方式就是描述这个计算图长什么样——至于计算图怎么执行、分发到哪台机器,最好都由底层的 system implementation 来管,程序员不需要关心。有了这个想法,你应该选择 Promise API 或事件驱动编程;有一个足够好的分布式数据库,加上一个足够好的语言来描述计算图,不就所有问题都解决了吗?这就是今天的 Serverless Computing(无服务器计算)。


无服务器计算与以计算为中心的传统架构

以前建网站,你会租一个服务器,有固定 IP,再去域名厂商买个域名(.xyz 的域名很便宜,大家可以去试试,搭一个自己的个人网站)。在这种模式下,一切以服务器为中心——你 SSH 连上去,跑一个 nginx,配置好,这就是典型的以计算为中心的思路。

Serverless 则告诉你:不要有"server"这个概念,应该以数据为中心。本质上,数据是一种状态——有多少用户、哪些 API key 是 inactive 的、每个 API 用了多少量……所有的增删改查业务逻辑,都是一个事件驱动的处理过程。


事件驱动架构与云函数部署

这不就是 JavaScript 里那种面向事件编程最容易实现的方式吗?所以我们真的可以用 JavaScript 来写数据中心里的程序。

比如,AI 帮我写了一个基于 Amazon S3 的 Serverless 程序:这是一个 event handler,从 HTTP header 里读取 Authorization 字段,找到 API key,然后去数据库里查这个 key 是否合法。如果不合法,就返回 401;如果检查通过,就去做 LM Inference。

把这个函数部署到云服务厂商上,剩下所有问题就都不是我的了,都是 infrastructure 层的问题。这样写程序,就可以 write once, planet scale——只要云厂商能扛住,当请求突然涌入时,云厂商会动态分配更多服务器,峰值过后再收回。


云厂商按需租用与计算图

云厂商会不断预测你的业务量,提前预留服务器,和你谈好一个非常低的 function call 价格,相当于按需租用服务器。你只需要写出计算图是什么,C10M 的扩容问题就交给云厂商了。

当然,Function-as-a-Service 并不是那么简单:你的这段代码随时都可能消失,Service 可能会重启并从头再运行一次。


Service 函数的幂等性设计

因此,绝大多数 Service function 都应该是幂等的(idempotent)——这是你们在离散数学课里学过的概念:同一个操作做多次,结果应该是一样的。

比如如果你想做计费,写成 t = load(sum); t++; store(t),如果 store 完成了而机器 crash 了,重做一遍账就会被记两次。更好的写法是:生成一个随机 key,把这个 key 加入一个 Set,sum 就变成这个 Set 的大小——无论做多少次,结果都一样,因为 Set 里重复的 key 只计数一次。

这个 idempotent key 应该在 Service function 刚开始调用时就生成(即请求进入系统时被 assign 的唯一 key)。只要你的程序是幂等的,就可以放心大胆地交给分布式环境来容错,从而得到一个非常可靠的系统。


云端存储:数据中心 SSD 集群与数据可靠性机制

你不用担心租用的服务器 crash——在数据中心里租用的服务器本来就非常可靠。你有没有注意到,在云厂商上租服务器时,存储和计算是分开计费的?

在实际的数据中心里,一个计算节点(有 CPU 和内存)通过超高性能网络连接到一个 SSD 集群。你写了一个 a.txt,看起来是往本地文件系统写,实际上是往这个 SSD 集群里写——而且会自动写两份或三份副本,数据非常安全。

这其实就是云厂商的"独门秘诀":你的数据进了他们的存储集群,而且一般文件系统不加密的话,他们还可以做去重(deduplication)。比如你和其他用户的虚拟机里都有同一个版本的 libc,这个文件完全一样,SSD 集群发现后只把引用计数加一,不重复存储。

结果就是,即便有三份副本,实际占用的存储总量可能还小于你上传的数据量——写放大比(write amplification)小于 1。你看,云厂商收你 1 GB 存储的钱,实际上在集群里占用的总空间可能不到 1 GB。某种程度上,我觉得这也是理所应当的——我们得到了服务,他们获得了收入。


LM Inference 与 Transformer 循环优化

现在我们知道了 API key 相关的增删改查是怎么实现的,剩下只剩一件事:做 LM Inference。本质上,大语言模型就是从一个条件概率函数上采样。

如果你们看过 gpt2.c 的源代码,整个代码的核心就在 forward 函数上——一个正向推导的循环,循环的每一层就是一层 Transformer。看起来很高大上的 Transformer,其实就是一大堆数学计算:一大堆数字经过一层层函数,得到另一大堆数字,比如 (l * B + t) * 4 * C 这样的下标运算,算出每个参数在数组里的位置。

这里面有 matmul_forward(矩阵乘法前向传播)和 attention_forward,这两个函数是最耗时的。理论上,你们去优化它就够了——我就这样把实验的答案告诉大家了。


SIMT 编程方式与 Transformer 架构优势

你们会看到,这些函数都是特别工整的大循环,比如:

ounter(lineounter(lineounter(linefor (int b = 0; b < B; b++)    for (int t = 0; t < T; t++)        for (int h = 0; h < NH; h++)

这不就是 SIMT 最喜欢的编程方式吗?就像我们用 CUDA 加速 Mandelbrot 集——for x in [0,W]; for y in [0,H],对每个像素进行渲染。Transformer 也是如此,代码结构看起来不长,但里面运行着很多深刻的道理。

人类花了很长时间做了大量实验,那篇著名的 Scaling Law 论文才证明了:Transformer 架构在处理长上下文模型方面,确实比 LSTM 更好。关于 Tensor 这个概念:一个数字叫标量(scalar),一个数组叫向量(vector),一个二维数组叫矩阵(matrix),更高维的数组就叫张量(tensor)——没什么神秘的。


为什么需要 Tensor:从 ImageNet 讲起

为什么需要 tensor?因为哪怕在深度学习刚火起来的时候,第一个爆火的应用是 AlexNet——揭开了深度学习的序幕,在 ImageNet 上大幅刷新了历史纪录。当时所有人都觉得手工特征已经到头了,Geoffrey Hinton 带的团队证明了深度学习的潜力。

图像是一个矩阵(二维数组),但仅仅一个矩阵还不够。上节课讲到,有些聪明的人试图用 Pixel Shader 来做矩阵运算,但如果要用深度神经网络处理图像,就不仅仅是一个矩阵进、一个矩阵出的问题了。


图像作为多维矩阵:数据结构与计算开销

首先,每张图像有 RGB 三个 channel:彩色图像需要三个整数(红、绿、蓝)来表示一个像素颜色,所以它是三个并排的矩阵。经过神经网络卷积后,channel 数量会越来越多。

还有 batch 的维度——如果你做 mini-batch 训练,里面有多份训练数据,整个结构又要被复制好多份。于是最终可能是一个 100 × 100 × 3 × 64 × ... 这样的高维数组——这就是 tensor。


Channel 与 Self-Attention 基础概念

深度学习继续发展,到 Transformer 时代,出现了一个跨时代的发明:Self-Attention。每一层 Transformer 都像是在读一本书——我花了一点时间想了这个类比,帮大家理解什么是今天的大语言模型。


大语言模型 Attention 机制与 QKV 原理

大语言模型做的是 next token prediction:给定一段输入,预测下一个 token。这个"要补全的句子"就是 Q(Query)——每次都不一样。还有 K(Key)和 V(Value):K 就像是书的目录,V 就是书的具体内容。

模型会把 Q 和 K 放在一起,从 V 里找出对于补全这个 token 最有用的部分(不重要的部分权重很低),然后做一个 softmax 再乘以 V,形成一个很大的向量。这个向量就是当前的"短时记忆",相当于你把书里的内容针对这个问题消化了一遍。

消化完之后,再把这个"短时记忆"传给下一层 Transformer——就像你根据当前的问题查书,查完书在脑子里形成一个想法,经过几层 dense 神经网络计算,再把问题重写一遍,再往上传,再往上传。每过一层,信息密度越来越接近最终要输出的那个 next token。最有意思的地方是:越到后面的层,你越来越不知道自己"看到"的是什么——那个表示已经高度抽象了。书里的 K 和 V 也都是学出来的,不是手工设计的。我们普遍认为这个架构的潜力还没有到头,它是否是最优的架构,也还没有定论。


矩阵运算的 PTX 指令优化

如果你们回去看 llm.c(我的 gpt2.c 是从 llm.c 裁出来的),它有一个 CUDA 版本的代码,和我们的 mandelbrot.cu 很像。你会发现 attention_forwardmatmul_forward 这些函数和 Mandelbrot 的结构非常相似,因此完全可以用各种并行化方式来加速——多线程 spawn、SIMD 或 CUDA 均可。

这里面最核心的运算(最内层的循环,执行最频繁的)就是一个内积(inner product)——本质上是两个很大的向量,对应元素相乘再累加,完全可以用 SIMD 的 FMA(Fused Multiply-Add)指令来实现。在 CUDA 版本里,矩阵乘法的 GPU kernel 会把所有参数(outinputweight 等)发到 GPU 上,GPU 立即开始执行。


GPU 串行执行与计算图合并优化

但 GPU 会把所有向 GPU kernel 的调用全部排队,等到第一个 kernel 执行完再执行第二个……也就是说,kernel 和 kernel 之间是串行的。每个 kernel 本身是高度并行的 SIMT 程序,但当 warp 里大多数线程都执行完、只剩少数几个"尾巴线程"时,GPU 利用率就会从很高跌到很低。

你会自然想到:能不能把所有 kernel 打包成一个 kernel?下一个 kernel 本质上只依赖上一个 kernel 里某几个计算的结果,把计算图拼起来,就可以更充分地利用 GPU 算力。于是你就发明了 FlashAttention——这是一个在现实中被广泛应用的技术。


CUDA 优化 GPT 训练

我们要写一个 CUDA 程序来完成 GPT 的训练,如果想让性能更好,就要思考一个更深的问题:我们本质上想 spawn 很多 worker,但任何一条指令都有译码的代价。SIMD 摊薄了译码代价,SIMT 也摊薄了译码代价,那能不能在 SIMT 里引入 SIMD?答案是可以的。

GPT 的核心运算非常规则(regular),都是矩阵运算。SIMT 里,每个线程通过 thread ID 算出 base + row * stride + col 这样的地址,然后进行 load 或 store,从而实现高带宽的内存访问。但这条地址计算指令本身也有代价——如果想把能效比做到极致,你连这条指令都不想要,你想要一条直接做矩阵乘法的 FMA 指令。


Tensor Core 与矩阵乘法指令

于是你就发明了 Tensor Core。NVIDIA 的 GPU 里有 Tensor Core,它的核心功能是:把一个 M × K 的矩阵 A 乘以一个 K × N 的矩阵 B,得到一个 M × N 的矩阵 D(即 D = A × B + C)。

所以 Tensor Core 本质上就是矩阵乘法。NVIDIA 完全可以叫它"Matrix Multiplication Extension(MMX)",但那个名字和 Intel 的 Multimedia Extension 撞了,而且显然太土了。NVIDIA 吸取了教训,给了一个更现代的名字:Tensor Core——虽然它做的本质上就是矩阵乘法,而不是更广义的张量运算。


矩阵存储与 Tensor Core 访存优化

但真正的 GPU 设计者面临的挑战并不只是"做一条矩阵乘法指令",而是内存的移动和布局优化

矩阵乘法的核心是"一行乘一列"。无论用行优先(row-major)还是列优先(column-major)存储矩阵,总有一个矩阵的访问是不连续的,无法避免 cache miss 问题。现代的解决方案是把矩阵分成一个个小块(tile),每个 tile 能完全放入缓存,从而实现高效计算。所以你会在各种官方博客里看到 tile、tiling 这些词——这都是因为硬件的内存线性寻址限制,不得不做的分块处理。

真正的 Tensor Core 要解决的是多维数据的搬运:压缩解压缩、跨 stride 访问、异步同步、内存布局转换(如转置)等。新一代 GPU 上有专用的 bulk tensor copy 指令,支持稀疏数据拷贝和零开销的转置——其目的就是让 CUDA kernel 能更高效地运行在 GPU 上。

这就是极致压榨性能的结果。如果你直接看手册,会被海量信息淹没。你真正需要的,是把时间拨回到 1997 年,去看看 Intel 是怎么做 MMX 的,当时的经验和教训是什么——然后你就会发现,历史惊人地相似。


AI 算力生态与 UNIX 历史的惊人相似

这两天有一个很有意思的新闻:NVIDIA 的市值已经超过了印度所有股票的总和,也就是说一个公司的产业体量超过了一个世界大国。这是一个 10 万亿美元量级的产业生态。

如果你回顾计算机硬件和软件发展的历史,你会发现历史真的惊人地相似。你们对 UNIX 比较熟悉——从底层系统调用(分页等机制)慢慢长出了今天看到的一切。同样地,从 GPU 加速器的生态上,也长出了今天人工智能应用的一切。

最底层是 GPU。DeepSeek 这次用华为升腾的卡来做推理,是一个非常大的进步(传言他们因为适配国产卡而推迟了发布,但没有确切证据)。在 GPU 和 CUDA 之上,还有一层非常重要的库函数,比如 cuBLAS(Basic Linear Algebra Subprograms)——提供矩阵乘法等核心运算。

就像英特尔发布了 MMX 但如果没有人为它写汇编就没法发挥性能一样,为了用好 Tensor Core,内存带宽、内存布局、访问模式、矩阵分块大小……这些都和底层硬件紧密相关,甚至对不同代 GPU 都要编译出不同的代码才能达到最优。cuBLAS 就是随着 CUDA 持续更新的这样一个库,很像是 libc 随着硬件体系结构更新而更新——当你的硬件有了新功能,libc 里的 memcpy 就会利用 AVX 指令集里的 YMM 寄存器做更长的 load/store 来提速。

在 cuBLAS 之上,还有 NCCL(通信库)。再往上,就是 AI 应用生态——AI 应用需要的是算子 kernel 的 fusion(融合)技术,比如 FlashAttention:把多层计算打包成一个计算图发给 GPU。再往上是训练框架、推理框架,以及更高层的 PyTorch、TensorFlow——用更高级的方式描述计算图,最终被编译成调用 FlashAttention → cuBLAS → CUDA kernel 的链路。

对照 UNIX 生态,你在网上能看到的 Ollama、Open WebUI、Claude Code……能想到的一切都有人在做,和 Linux 生态一模一样。


GPT-2 1.5B 模型与 HTTP 请求处理流程

如果你的推理集群上跑的是 GPT-2(1.5B 参数),问题几乎就解决了——相当于 HTTP 请求到达业务节点,业务节点做一个数据库增删改查,事情就完了:直接起一个 kernel,完成整个推理流程。

但如果今天的模型是 1.6T 参数,加上很长的 context,这就非常困难了。一张 GPU 卡没有 1.6T 的显存,你必须把计算分到很多张卡上,而且 self-attention 的计算量随序列长度 N 平方增长,非常非常大。


PD 分离:大模型推理基础设施

所以今天大语言模型的推理服务——就像水和电一样的基础设施——普遍做了一个叫 PD 分离(Prefill 和 Decode 分离)的架构。

我们说 attention 机制像是"看书"。实际上,如果你的 Q 是之前用过的(即历史 context 中的 tokens),那所有对应的 K 和 V 都可以缓存起来,保存到 KV Cache 中,避免重复计算。


KV Cache 机制与 Q 改写生成

所以你会看到 DeepSeek 的 API 有 Cache hit 和 Cache miss 两种计费价格:Cache hit 意味着 KV Cache 还在显存里没被换出(之前 prefill 过了,还"热"着);Cache miss 就意味着要重新 prefill,代价相当高。

Decode 部分需要读取完整的 KV Cache,然后根据当前的 Q,每过一层 Transformer 都"查一遍书"、更新短时记忆、改写 Q,再往上传,最终生成下一个 token。

有意思的是,去年 DeepSeek 做推理的工程师在 ChinaSys 做报告时,开篇第一句话说:你们在体系结构课和操作系统课上学过的所有概念,在 DeepSeek 这里都用上了——但关于 Memory Hierarchy 的那些具体延迟数字和通信速度,都和教科书上的不一样。


用 Profiler 分析系统各部分行为

但你们在这门课上学到的那些分析问题的方法——比如"想知道系统的每个部分到底做了什么,就用 Profiler 去分析每个部分的行为"——这些肌肉记忆,在真实的生产系统中都有非常大的用处。


Pipeline 与 Serverless 返回 Next Token 的处理流程

在推理集群里有 Tensor Parallelism、Pipeline Parallelism,以及 MoE(Mixture of Experts)模型……最终终于返回了一个整数,就是你的那个 Next Token。

这个 Next Token 返回来以后,就像刚才那段 Serverless 代码一样,还要做很多事:审计(就像"屏蔽朋友圈"的例子),记账,更新 Dashboard,最后生成一个 HTTP Streaming response。实际上我们可以看到:response 的第一个 chunk 里有一个 system_fingerprint 字段(比如 fp8-kv-cache-2026-04-02),然后才开始吐 token。

这个旅程其实没有终点——token 就这样回来了,在数据中心里兜了一圈。


先进终将过时,永远质疑当下

你会发现,这个世界一直都在进步。UNIX 时代,UNIX 就是最先进的东西;云计算时代,数据中心里的增删改查就是最先进的东西;今天 AI 时代,PD 分离的推理就是最先进的东西——而它们总有一天会过时、会被证明是错的。

所以你可以安全地假设:现在全世界都错了。这样想是有道理的:这是一个 10 万亿美元的产业,只要你把一件对的事情做好,就可以挣到很多钱,所以你应该去做。不仅如此,Scaling Law 也只证明了 Transformer 可能比 LSTM 更适合训练长上下文模型,但最好的架构在哪里,现在还没有人知道


呼吁避免学术裁缝,专注真正创新

我知道你们很多人会去做人工智能相关的研究,会去设计新的神经网络。我希望大家不要"错上加错",不要做那种"学术裁缝"——把 A、B、C、D 四篇论文各取一块,拼在一起发一篇。

在我刚才描述的这个 big picture 里,在这个 10 万亿美元的产业里,生态位里有无数的空缺。你完全没有必要在一个很小的地方做一个没有人 care 的东西。每年 AI 顶会投稿几万篇,其中绝大多数我认为对学术界其实是有害的。


从第一性原理找空白生态位

你们完全可以不被服从性测试折磨,而是回头从**第一性原理(first principles)**出发,想一想这个生态位里面到底还有什么事情做错了,然后大胆地去做——这是非常重要的。这是一个 10 万亿美元的产业,你去做,是非常值得的。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-25 13:16:43 HTTP/2.0 GET : https://b.460.net.cn/a/588946.html
  2. 运行时间 : 0.113217s [ 吞吐率:8.83req/s ] 内存消耗:4,459.84kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=0edbe141ee9bb52d4d6905a3662ab637
  1. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/database.php ( 2.47 KB )
  34. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/runtime/temp/b35eef690f41e64ad9e1c098cfc7d3bc.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/b.460.net.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000845s ] mysql:host=127.0.0.1;port=3306;dbname=b460;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001604s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000820s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000802s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001636s ]
  6. SELECT * FROM `set` [ RunTime:0.000684s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001767s ]
  8. SELECT * FROM `article` WHERE `id` = 588946 LIMIT 1 [ RunTime:0.001324s ]
  9. UPDATE `article` SET `lasttime` = 1782364604 WHERE `id` = 588946 [ RunTime:0.001380s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 65 LIMIT 1 [ RunTime:0.000686s ]
  11. SELECT * FROM `article` WHERE `id` < 588946 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.004119s ]
  12. SELECT * FROM `article` WHERE `id` > 588946 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001155s ]
  13. SELECT * FROM `article` WHERE `id` < 588946 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001871s ]
  14. SELECT * FROM `article` WHERE `id` < 588946 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.003661s ]
  15. SELECT * FROM `article` WHERE `id` < 588946 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001895s ]
0.115015s