别再吵Linux和Windows谁好了:真正该比的是中断风暴和调度延迟

🔑 关键词:中断风暴,调度延迟,内核抢占,实时性,操作系统对比

📖 摘要:从处理器的中断风暴、内核调度延迟和驱动模型这三个没人提的角度,重新审视Linux和Windows的内核差异,以及为什么你可能根本不需要换系统。

先说点得罪人的话

图片

我用了十年Windows,八年Linux(Ubuntu和Arch都折腾过),macOS也在公司配的MBP上天天摸鱼。但今天我不想扯什么“Linux是开发者的天堂、Windows是小白的老婆”这种嚼烂的梗。我想聊的是三件你在参数对比表上看不见的事:中断风暴(interrupt storm)怎么把一台机器搞成PPT、内核抢占模型如何决定你打游戏时的卡顿是不是玄学,以及驱动到底是在帮你还是在欺负你的CPU。别急着关页面,这文章不是写给内核大佬看的——是给那些觉得“系统卡但找不到原因”的普通人看的。

中断风暴:比死机更恶心的慢性自杀

图片

先解释一下。CPU不是超人,它没法同时处理鼠标点击、网卡收包、硬盘写数据。所以硬件设备会发一个叫IRQ的中断信号给CPU,CPU先暂停手头的事、跑去处理这个设备。Windows和Linux都有中断机制,但处理方式完全不同。Windows用的是中断对象(KINTERRUPT)加上线程化DCP(延迟过程调用)的混合架构。也就是说,当一个设备疯狂发中断(比如某款螃蟹网卡驱动抽风),Windows会让这个中断的优先级被拉低、丢到一个专用线程里排队慢慢磨,从而保护前台正在跑的进程。而Linux呢,经典的内核是硬中断上下文里必须快速处理,如果处理不完就转成softirq(软中断)在之后补处理。问题在于:当网卡或者NVMe固态因为固件bug连续触发每秒几万几十万次中断时,Linux的CPU 0号核会被彻底淹没,你会在top里看到si(软中断占用)飙到90%以上,鼠标都开始掉帧。

我自己的亲身经历是:一台ThinkPad X250(i5-5300U)装Ubuntu 20.04,只要插上某个USB 3.0的Realtek读卡器,系统就间歇性卡死——不是死机,就是打开终端要等五秒。查了dmesg发现是rtsx_pci在疯狂报中断。折腾了三天,最后在GRUB里加了threadirqs参数强制把所有中断线程化才解决。这也是为什么Linux服务器上高手都会用irqbalance或手动把网卡中断绑到除CPU0之外的核上——本质上是让一个物理核专门去挨打,其他核保持干净。而Windows这种“中断线程化”的设计虽然牺牲了一点点延迟,却天然能防止单个设备把整个调度器拖垮。这不是Bug,是设计哲学的差异。可悲的是,绝大多数用户根本不知道自己的后台卡顿是中断风暴引起的,只会习惯性地怪“国产软件全家桶”。所以你想用Linux,第一课不是学命令,而是学会看cat /proc/interruptsmpstat -I CPU

调度延迟:你的游戏卡顿不是显卡的锅

图片

再说调度器。Windows从NT 4时代就用多级反馈队列(MLFQ)配合优先级提升机制,前台进程的窗口(尤其是你正在按键盘鼠标交互的那个)会被动态加到极高的优先级,并且有很长的时间片配额。这就保证了你在Word里打字或者玩CS:GO时,即使后台有杀毒软件在扫描全盘,前台该有的响应还是能拿到。Linux后来虽然也引进了CFS(完全公平调度器)以及近年来的EEVDF(谷歌提的那个,现在已经进了6.6+内核),但公平不等于响应快。CFS的目标是让每个进程在统计上获得相等的CPU时间,所以在桌面负载下,当一个实时性要求没那么高的后台任务(比如编译、系统更新)占用了大量CPU时间,你的输入进程往往会被排到几千个runqueue条目后面——当然,内核也有sched_autogroup和nice值,但默认参数下,桌面交互延迟依然很看脸。

我自己做的实验:同一台台式机(锐龙3600,32GB,RTX2060),装Windows 10和Ubuntu 22.04,用cyclictest跑默认配置测试调度延迟。Windows下因为没法直接跑cyclictest(得用WSL,有额外开销),我用的是Windows自带的latencymon测DPC延迟。结果很有意思:Windows在空闲时DPC延迟偶尔会飙到200微秒以上,而Linux在默认配置下用cyclictest测平均只有8微秒,但最差情况(max latency)偶尔能冲到2毫秒甚至更高——那是因为碰到CFS唤醒延迟以及某些不支持CPU无偏好场景的驱动。如果你玩那种对显卡要求不高、但特别吃输入帧率的老游戏(比如《英雄联盟》或者《CS:GO》的创意工坊图),Linux上经常出现帧数很高但操作发飘的情况。说老实话,Valve的Proton映射层已经让Windows游戏在Linux上跑得不错了,但调度器那点微小的不响应,还是能让你在竞技游戏里被那1%尾延迟坑死。

图片

或许会有人说:你不会用chrt调优先级吗?是的,我试过。把游戏进程chrt --fifo 95丢死循环里确实管用,但这会导致你CPU的交互核被独占,连你从另一台电脑SSH进来都卡。而且现代游戏是几十个线程在跑,你只能调主线程,剩下几十个子线程照样在CFS里排队。Windows的价值就在这:它那套动态优先级提升经过几十年商业游戏磨合,已经能自发识别“这是前台窗口,所有相关线程(包括子线程)都该被倾斜”。Linux桌面从来没被游戏厂商当过头等公民,KDE和GNOME的优先级调优插件也就止步于setpriority。所以我的观点是:如果你追求的是“人机交互的确定性”,Windows胜过Linux一百倍;如果你要的是“后台吞吐量的公平性”,Linux胜过Windows一百倍。这两个东西根本不是一个维度,却总是被键盘侠放在一起比。

驱动、固件和生态:到底谁在当脏活累活

图片

这些年吹Linux的一个流行话术是“Linux驱动都在内核里,不用装驱动”,这是纯粹的骗子。Linux把驱动分成内置(built-in)和模块(.ko),但大部分硬件的固件(firmware)仍然是闭源二进制blob,比如你的WiFi网卡、独立显卡、声卡,它们都需要非自由的固件文件,由内核在加载模块时从/lib/firmware里读入。而Windows的驱动模型更复杂也更霸道:一个驱动要通过微软的WHQL测试签名才能推送,但真正给老显卡、老声卡倒屎的往往是驱动里的自带控制面板(比如NVIDIA控制面板存了一堆服务)和那些伴随驱动安装的软件狗。Windows的ntoskrnl.exe会为每个驱动建立一个设备栈,而设备栈里面的IOCTL调用动不动就阻塞线程,导致你看任务管理器里“系统中断”进程占用CPU高达30%——那是驱动在忙,不是Windows本身在忙。

我拿一台2012年戴尔OptiPlex 390做过干净对比测试:Windows 10 LTSC装完官方驱动后,空闲CPU占用2%-5%,但偶尔会有一个“WmiPrvSE.exe”翘到30%——这是标准驱动管理WMI的锅,完全没法修(只能禁用相关服务)。同一台机器装Debian 12,装完闭源网卡固件后,CPU空闲稳定在0.5%-1.2%之间,没有任何后台进程偷跳。但代价是什么呢?我在Debian上想调一下GPU的刷新率,得写一个xorg.conf的Modeline脚本,并且显卡驱动是nvidia-driver专有版本,每次内核一升级,NVIDIA的.ko就要重新编译签名,否则启动直接掉到VGA分辨率。那一刻我突然明白了:系统没有绝对的“干净”,只有你看得见的垃圾和你看不见的垃圾。Linux把驱动加载整个做成内核模块,让你觉得干净,实际上它把硬件初始化的复杂度推给了用户去学,去编译,去处理DKMS。而Windows用WMI那堆臃肿服务换取了“大部分显卡插上就能刷到60Hz”的体验。所以你说哪个更好?不如说哪个更配得上你这个人的耐心值。

我不会劝你换系统,我只会让你会打“perf top”

图片

所以我的结论是:操作系统之争本质上是“工程师的洁癖”和“普通人的惰性”之间的战争。Linux把控制权给你——但你需要自己会拆炸弹;Windows把控制权据为己有——但里面藏着一条随时会踢你一下的黑腿。macOS则是另一种极端:它用Mach微内核和XNU混合结构让驱动和安全模块都留在用户态,换来的是整机系统的极高稳定性——代价是你不能升级内存不能换SSD还得忍受Type-C只有一个口。你问我哪个最好?我只能说,如果你已经受够了Windows的碎片化性能,又没时间去开个Linux终端敲apt build-dep,那大可在macOS上养老。但如果你想真正看清一台电脑的运行本质——哪些中断在打你,哪个线程在饿肚子,哪块固件在扯淡——去折腾几个月Linux,然后再回来用Windows,你会突然觉得Windows那些“卡顿”有了原因,而你骂它是“垃圾系统”的词也变得更准了。

感谢你看到这里。这篇不是指南,更像是我的抱怨。上面说的方法和参数,我尽量写明了命令和实测数据,但如果你在自己的机器上没复现,也别骂我——硬件、内核版本、BIOS设置、甚至是天气都会影响调度器行为。这就是为什么操作系统永远是“你的操作系统”和“我的操作系统”的分歧。