你排的那一队,凭什么总是最慢的

上周在超市,我排了七分钟。隔壁那队换了四拨人。

我当时的结论是"我运气差",并且非常确信这一点——因为这种事不是第一次发生了。后来我把这个场景写成了代码,跑了 20 万个人,发现了一件让人不太舒服的事:这件事跟运气一点关系都没有,它是默认选项。

超市收银区俯视:五条队伍,其中一条明显更短、正在前进

下面所有数字都来自我写的一个离散事件模拟器:到达间隔和服务时间都按指数分布抽样(这是排队论里最"随缘"的假设,也是现实里最接近的),Node v24.16.0,本机 Linux x86_64,每轮 15 万到 20 万人,丢弃前 10%~15% 的预热样本。不涉及网络,只有 CPU 和内存。

基准场景:5 个服务台,每人平均服务 60 秒,平均每 14.29 秒来一个人。到达率 4.20 人/分,总服务率 5.00 人/分,利用率 ρ = 0.84。就是你周末下午那家超市。

# 一、"另一队更快"不是运气差,是默认选项

先做一个最朴素的测量:站在队伍里,看过去 90 秒每条队各服务了几个人。

随机挑一个时刻、随机挑一条队,69.14% 的时刻,至少有一条队比它服务得多。

那是不是因为慢的队里挤了更多人?我把所有正在等待的人按他们所在的队分组,再按"这队最近 90 秒的进展"从快到慢排序:

按最近 90 秒进展排名 挤着全场多少等待者
最快那条队 21.20%
第 2 20.57%
第 3 19.21%
第 4 19.96%
最慢那条队 19.06%

几乎是均匀的。换成"随机挑一个正在排队的人",答案也只是从 69.14% 变成 69.36%——差别可以忽略。慢队里并没有真的挤着更多人,因为五条队在统计上完全一样,"最慢"只是最近 90 秒的一次随机波动,下一分钟就换人了。

那 69% 这个数字是怎么来的?答案很无聊:五条队里,你恰好是跑得最快的那条,本来就是小概率事件。不是运气,是组合学。

具体一点:n=5 时,"过去 90 秒完成的人数严格多于其他所有队"——也就是你真的是全场最快那条——只占 12.75% 的时刻;"至少不比别人慢"(含并列)占 30.6%。剩下 69.4% 的时刻,你抬头就能找到一条比你快的队。

真正让这个数字变大的是你看的时机。

现实里没有人匀速抬头。人的抬头规律大致是:自己这条队不动的时候,才去看别人。我把这个行为写进模拟——"只有在我这条队过去 20 秒一个人都没走时,我才抬头":

队列数 n 随机时刻随机挑一条队 随机挑一个排队的人 只在自己卡住时抬头
2 36.44% 36.73% 42.87%
3 53.33% 53.46% 60.85%
5 69.14% 69.36% 76.74%
8 79.02% 79.19% 85.42%

从 69.36% 涨到 76.74%。而且这类"我自己卡住了"的时刻,占掉你整个等待时间的 75.79%——你四分之三的排队时间都在这种状态里,所以你四分之三的印象都是"别人在动,我不动"。

最后一层是记忆。随机选一条队时,等待时间的分布是这样:

p10 =   0.0 秒
p50 = 185.9 秒
p90 = 762.4 秒
p99 = 1592.6 秒
max = 2760.9 秒

最慢的那位比最快的那位多等了 46.02 分钟,而他们做的完全是同一件事、排的是同一种队。等最久的那 20% 平均等了 869.1 秒(14.5 分钟),最快的那 20% 平均只等了 1.2 秒。

你不会记得那 1.2 秒。你记得的是 14.5 分钟,而且你会把它当成"常态"。

一个人站在长队里,斜眼看着隔壁那条正在前进的队伍

# 二、蛇形队:看起来更长,实际快 85%

如果说上面那节是"为什么你的主观感受不可信",那这节是"有一个简单的改造能让所有人都变快"。

同样的 5 个服务台、同样的 4.20 人/分,只改一件事:把 5 条队合并成 1 条蛇形队,谁先到谁先上,哪个窗口空了就叫下一个。

排队方式 平均等待 标准差 p50 p95 p99 最坏 基尼系数
多队列(随机选一条) 312.3s 362.9 190.5s 1065.2s 1605.4s 2900.4s 0.58
多队列(选最短的) 83.0s 100.8 49.4s 286.1s 452.3s 1203.0s 0.60
单队列(蛇形) 44.7s 62.7 17.8s 177.5s 269.3s 506.6s 0.67

蛇形队对比随机选队:平均值 -85.69%,标准差 -82.73%,p95 -83.34%,p99 -83.23%,最坏情况 -82.53%。

几乎不用等(小于 1 秒)的人占比,从 16.51% 涨到 37.26%。

道理不难:多队列里,最典型的事故是某个窗口空着,而它那条队没人——因为你一旦选了队就被锁死了,隔壁那位买了 47 件东西,你的窗口已经空转了两分钟,你也只能看着。蛇形队消灭了这种"有人没事干同时有人没事干"的浪费。

但这里有个必须说清楚的副作用:基尼系数从 0.58 升到了 0.67。

蛇形队让"运气"变得更值钱了。37.26% 的人一秒钟都不用等,而剩下的人相对均值更惨——p95/p50 的比值从 5.59 涨到 9.98。所以蛇形队里排在尾部的人会觉得"这制度不公平",而他们的感觉在相对意义上是对的:他们确实比多队列时代绝对快得多(269.3s vs 1605.4s 的 p99),但他们的参照系变成了旁边那些一秒钟都没等的人。

机场安检的蛇形隔离带,一条队通向多个柜台

这也是为什么银行和机场爱用蛇形队,而超市不用——不是超市不懂,是购物车塞不进蛇形通道,而且超市靠"你一眼就能数出前面有几个人"来安抚你。蛇形队把这条信息拿走了:你只能看到一条望不到头的长龙,尽管它前进得比谁都快。

# 三、ρ 从 0.5 涨到 0.98,等待涨了 157 倍

这节是给所有做容量规划的人的。

还是 5 个服务台、服务均值 60 秒,只改到达速率:

利用率 ρ 到达间隔 平均等待 p95 最坏
0.50 24.00s 3.2s 23.1s 208.1s
0.60 20.00s 7.3s 47.5s 253.4s
0.70 17.14s 14.8s 80.0s 308.1s
0.80 15.00s 34.2s 149.7s 478.4s
0.90 13.33s 92.7s 316.4s 1015.0s
0.95 12.63s 217.0s 818.4s 2122.6s
0.98 12.24s 501.0s 1427.7s 2225.4s

ρ 从 0.5 涨到 0.98,不到一倍。平均等待从 3.2 秒涨到 501.0 秒,157 倍。

而且这条曲线最陡的地方在最右边:0.90 → 0.95 这五个百分点,等待翻了 2.3 倍;0.95 → 0.98 这三个百分点,又翻了 2.3 倍。

所以"下午三点银行开一个窗口也够用,五点半开五个窗口还是挤"不是错觉——下午三点 ρ 可能是 0.5,五点半是 0.9,这两者之间的差距不是 1.8 倍,是 29 倍。同样,"再加一个窗口就好了"在 ρ 已经 0.95 的时候是最有效的干预,在 ρ=0.5 的时候几乎没用。

暗背景上密集的光点挤过一处狭窄的瓶颈,随后散开

# 四、"10 件以下"快通道,是个精心设计的陷阱

这条标志牌几乎每家超市都有。我用它做了个实验。

假设服务时间 = 20 秒 + 2.5 秒 × 件数。60% 的人是小篮子(1–10 件,平均服务 33.8 秒),40% 的人是大车(11–60 件,平均服务 108.7 秒)。两个收银台,总 ρ = 0.85。

先算笔账,不用模拟:

快通道负载 = 0.6 × λ × 33.8 秒  = 0.54
普通道负载 = 0.4 × λ × 108.7 秒 = 1.16   ← 大于 1

普通道的负载是 1.16,意味着它每小时能处理的量小于每小时来的量。这个队会无限增长,永远清不空。

模拟证实了这一点。快通道确实很爽(小篮子平均只等 18.2 秒),但大车的等待是这样发散的:

第 N 位顾客到达时 最近 500 位大车的平均等待
1000 4970.3s
2000 9114.9s
4000 22282.4s
6000 35359.7s
8000 49524.9s

到第 8000 人时,推大车的人平均要等 13.8 小时。这不是"比较慢",这是系统在发散。

问题不在"快通道"这个想法,在切得太随意。快通道的本质是"按服务时间分桶",而分桶就意味着把本来共享的容量切成几块互相借不到的蛋糕。只要切得不对,其中一块必然过载。

我给它一个公平的机会:开 3 个收银台,其中 1 条快通道 + 2 条普通道(这样两条普通道各担 0.58,跟快通道的 0.54 基本持平):

方案 全体 小篮子 大车 最坏
[C] 三条通用道 37.1s 36.9s 37.3s 521.9s
[D] 1 快 + 2 普通 36.6s 21.0s 59.8s 863.9s

负载配平之后快通道终于不是灾难了:小篮子快 43.11%,大车慢 60.43%,全体快 1.21%。

看清这个结构:快通道从来不是在"提升效率",它是在重新分配痛苦——从 60% 的人身上拿走 43% 的等待,加到 40% 的人身上。全体只赚了 1.21%,这 1.21% 还是因为分桶略微降低了服务时间的方差。它流行的真正原因是那 60% 的人会投票。

超市快通道标志牌挂在空荡荡的通道上方,旁边的普通通道排着长队

# 五、波动从哪来,就从哪治

这是整篇文章里我最想留下的一条。

同样是 5 个服务台、ρ = 0.84、蛇形队,只改"随机性来自哪里":

到达 服务 平均等待 p95 最坏
随机 随机(M/M/5) 48.0s 191.9s 647.9s
固定 随机(D/M/5) 18.3s 90.0s 290.0s
随机 固定(M/D/5) 24.5s 92.7s 247.1s
固定 固定(D/D/5) 0.0s 0.0s 0.0s
随机 均匀 50~70 秒 24.8s 94.3s 256.4s

两件事:

一,让到达变规律(48.0s → 18.3s)比让服务变规律(48.0s → 24.5s)更管用。 这直接解释了预约制为什么有效:你没让医生变快,你只是让病人不再一窝蜂地来。

二,两边都固定,等待是 0。 不是"趋近于 0",是精确的 0——14.29 秒来一个人,每人服务 60 秒,5 个窗口轮流接,第 k 个窗口接第 k、k+5、k+10… 位顾客,间隔 71.43 秒 > 60 秒,永远追不上。

再看单服务台、ρ = 0.8 时,服务时间的波动本身值多少钱:

服务时间分布 平均等待 p95
指数分布(最随缘) 232.0s 812.1s
常数 60 秒 116.6s 383.6s
均匀 30~90 秒 126.5s 423.4s
均匀 50~70 秒 117.6s 387.6s
双峰(一半 20s 一半 100s) 168.1s 556.0s

232.0 / 116.6 = 1.99,正好是 2。这不是巧合,M/M/1 的排队时间恰好是 M/D/1 的两倍——排队论里少有的一个漂亮结论。

关键是倒数第二行:你不需要真的把服务时间压成常数。只要从"有时 20 秒有时 100 秒"变成"都在 50~70 秒之间",等待就从 168.1 秒掉到 117.6 秒,几乎摸到了理论下限。抹平长尾,比压缩平均值划算得多。

我二分查了一下这个"抹平波动"到底值多少提速:让服务时间保持指数分布、只压缩它的均值,要多快才能追上"波动全消"的效果?答案是 52.06 秒——也就是把服务时间的波动彻底消除,效果等价于让每个人平均快 13.23%,而且不需要多花一分钱。

放到真实场景:一家店与其重金上更快的收银系统,不如先消灭"偶尔遇到一个要核对价格的、要退货的、要找会员码的"。那几个极端值制造的长尾,比平均速度重要得多。

# 六、加一个窗口,还是让窗口快 20%?

ρ = 0.84 的 5 个服务台。你手上有一笔预算,可以让总容量提升 20%。两条路:

方案 平均等待 p50 p95 最坏
基准:5 台,ρ=0.84 45.5s 16.7s 180.4s 547.8s
加一台:6 台,ρ=0.70 11.1s 0.0s 62.0s 309.8s
提速 20%:5 台,ρ=0.70 12.3s 0.0s 66.5s 231.0s
两者都做:ρ=0.58 3.4s 0.0s 24.2s 163.5s

两条路都把 ρ 从 0.84 降到 0.70,效果也几乎一样:花 20% 的资源,等待时间降了约 75%。 这就是第三节那条非线性曲线的正向用法——你在悬崖上往下退一小步,收益是巨大的。

加一台略优于提速 20%(11.1s vs 12.3s),因为 6 台共享一条队的"池化"效果比 5 台更好。但差别只有 1.2 秒,真正重要的信息是:别在 ρ 已经很低的时候再加人。 ρ = 0.58 的"两者都做"只把平均等待从 11.1 秒降到 3.4 秒,性价比远不如第一次那 20%。

银行营业厅里的单条蛇形队列和电子叫号屏

# 七、一个不需要模拟就能知道的公式

最后给一个能在脑子里跑的工具,Little 法则:

L = λ · W

系统里的平均人数 = 到达率 × 平均停留时间。我在模拟里验证了一次:时间平均系统内人数 8.05 人,到达率 4.22 人/分,平均停留 114.5 秒(1.91 分),λW = 8.05,误差 0.00%。

它简单得不像话,但它的威力在于它跟到达分布、服务分布、队列结构全都无关。所以你可以用它反过来查自己:

  • 收银台前平均站着 8 个人,每人平均待 2 分钟 → 每分钟必须有 4 个人被服务完。做不到,队就会一直变长。
  • 你想把停留时间砍一半,在到达率不变的前提下,系统里的人数就必须砍一半——没有第三条路。
  • 客服说"我们积压了 300 个工单",你知道每周新进 100 个 → 平均处理时长是 3 周。不用看任何报表。

排队系统里绝大多数直觉都是错的,但这条不是。

# 八、一份清单

  1. "另一队更快"是组合学,不是运气。 5 条队时 69.14% 的时刻你落后于至少一条队;如果你只在自己卡住时抬头,是 76.74%,而这类时刻占你等待时间的 75.79%。
  2. 你记住的是尾部。 随机选队时 p50 是 185.9 秒,最坏是 2760.9 秒,差 46 分钟,而原因只是"选了那条队"。
  3. 能合并就合并。 5 条队合成一条,平均等待 -85.69%,标准差 -82.73%。这是全表性价比最高的一行。
  4. 蛇形队让"运气"更值钱。 基尼系数 0.58 → 0.67,37.26% 的人一秒不用等,剩下的人相对更惨。它更快,但不一定让人觉得更公平。
  5. ρ 超过 0.8 之后,每一次增量都很贵。 0.5 → 0.98 不到一倍,等待 157 倍。
  6. 分桶要按负载切,不要按人数切。 "10 件以下"把我模拟里的普通道切成了负载 1.16 的死局。
  7. 先治波动,再治速度。 抹平服务时间的长尾等价于免费提速 13%;让到达变规律(预约制)比让服务变规律更管用。
  8. 在悬崖边上加容量最划算。 ρ 0.84 → 0.70 花 20% 资源换 75% 的等待下降;ρ 0.70 → 0.58 只有 69%。
  9. 记不住别的就记 L = λW。 它对任何排队系统都成立,包括你的收件箱。

回到开头那七分钟。我现在知道那七分钟里大概有五分半我是"卡住"状态,而在这五分半里我看隔壁,有 76.74% 的概率会觉得它在动。

排队的痛苦从来不是那 312 秒,是"我本可以不排这么久"的怀疑。蛇形队解决的其实是后半件事——它把"选错队"这个选项从游戏里删掉了。你还是可能等很久,但你已经没有可以责怪的自己了。