2015年股灾最惨烈的那几周,我每天都会收到大量读者的私信。其中有一封我至今保留着。发信人是一个在杭州做嵌入式开发的工程师,他在信里写了这么一段话:
“我把房贷的钱挪去补仓了。本来下周一扣款,我以为这周一个反弹就能出来,结果今天又是跌停。我现在盯着银行发来的扣款提醒,手在发抖。如果周一扣款失败,我的征信会留记录。如果我把股票割了,这笔亏损够我还三年房贷。”
他把房贷的钱挪去补仓。六个字,两层灾难。第一层,他打破了内核层和系统服务层之间的通信协议,让本该单向向上的资金流反向渗透。第二层,他把一个需要绝对稳态的长期负债调度任务,扔进了一个高频振荡的随机环境里。他以为自己在做资金周转,实际上他是在用中断处理程序跑一个需要持续运行几十年的守护进程。
他的故事,就是我们这一节要讲的全部内容。
可靠驱动:那笔你不该感觉到它存在的钱
你写过Linux驱动吗?
如果你写过,你一定体会过一种奇特的感受:写完之后,你就忘了它的存在。一个成熟的驱动——比如一个SATA控制器驱动、一个USB host驱动——它不会有惊艳的日志输出,不会在系统启动时弹出炫酷的界面,不会申请创新专利。它只是在每一次你读写硬盘、插拔U盘的时候,默默地、准确地、不眠不休地完成它分内的IO操作。你不感知它,是它最大的成功。
你的家庭财务系统里,哪些资产应该扮演这个角色?
国债。大额存单。高等级信用债基金。银行结构性存款。储蓄型国债。
这些资产有一个共同特征:你感觉不到它们的存在,但它们每年都在稳定地、可预期地输出利息。这种输出不像股票的涨停那样刺激你的多巴胺,也不像比特币的暴涨暴跌那样占据你的社交媒体时间线。它们就是在你的资产列表最底层,默默地、无趣地、极度可靠地跑着。
很多人——尤其是工程师——看不起这些“驱动级资产”。他们的理由听起来很理性:国债一年3%不到,通胀都不一定跑得过,有什么好配置的?
这个想法的问题在于,它用评估应用层性能的标准,去评估驱动层的价值。一块SATA驱动的代码量可能只有几万行,比不上一款3A游戏的零头。但如果没有这块驱动,你的操作系统连硬盘都识别不出来,游戏根本装不进去。国债的收益率是不高,但如果没有这些在任何市场环境下都能稳定兑付的底层资产,你的财富系统在极端的金融风暴中可能连交易软件都打不开。
2008年金融危机最恐慌的时刻,全球几乎所有风险资产同时崩盘。股票跌,商品跌,连黄金都在跌。只有一样东西在涨——美国国债。当时市场里有一句话:当全世界都在找出口的时候,国债是唯一一扇不管踹了多少脚都能打开的门。
你的资产组合里,有没有这扇门?
它不需要很重。对于大多数三十来岁的工程师,纯固收资产占总资产的15%到25%就足够了。但“足够”的前提是它真的存在,而且你不去动它。你不能在市场暴跌的时候对自己说“反正债券流动性好我先卖了去抄底”——你这等于把SATA驱动卸载了去给显卡超频,短期可能跑分更高,但下一次你要读硬盘的时候,系统直接蓝屏。
长周期调度:房贷是你系统里优先级最高的守护进程
我认识的所有工程师里,能把房贷这件事从技术层面讲清楚的,是一个在华为做了十年基站调度的系统架构师。
他说:“你们把房贷理解成每个月要还一笔钱,这太浅了。房贷本质上是一个硬实时任务。它有严格的截止时间,有不可协商的优先级,一旦调度失败,后果不是性能下降,是系统性故障。”
硬实时。这个术语用得极其精准。
你写过的所有程序里,绝大部分是软实时的——错过了截止时间,体验变差,但不会死人。视频通话卡了一下,你骂一句继续聊。网页加载慢了两秒,你刷新一下继续看。但有些任务是硬实时的——安全气囊必须在碰撞后15毫秒内弹出,晚了0.1秒就是另一个结果;反锁刹车系统必须在检测到打滑后5毫秒内介入,超时就是事故。
房贷就是硬实时。每个月的扣款日,银行从你的指定账户划走约定的金额。晚一天,你的征信报告上多一笔逾期记录。连续晚三个月,银行可以启动诉讼程序。连续晚六个月,你的房子可能被法拍。
一个硬实时的任务,需要什么调度条件?需要独占的、不受其他进程干扰的、在截止时间之前绝对可用的资源。
你写给房贷的资金来源,必须满足三个条件:第一,它必须在扣款日之前就已经存在你的还款账户里,不能靠“明天一个反弹我就转出来”;第二,这笔钱的来源必须是内核层或系统服务层——你的工资、你的固收利息、你的租金收入,不能是应用层的高风险投机收益;第三,这笔钱的金额必须至少覆盖三个月的扣款,用来缓冲任何可能的收入中断。
第三个条件,很多人第一次听到的时候不理解:“我每个月发工资当天就还贷了,为什么要提前预留三个月?”
因为你假定工资是永远按时到达的。但这个假定,我们在2.3节的主时钟段落里已经彻底拆解过了。你的主时钟可能停振。当它停振的时候,如果你的房贷还款账户里只够下个月的扣款,你还有最多三十天找到下一个时钟源。但如果你的还款账户里已经躺好了三个月的月供,你的窗口就延长到了九十天。这九十天,就是你的备用时钟启动、看门狗介入、或者你找到新工作的过渡时间。
这就是硬实时任务的工程标准:永远不要让你的调度系统依赖“一切正常”这个假设。一切正常的时候,谁都能调度。真正考验调度器质量的,是一切不正常的时候。
公积金:专属加速器,不用等于浪费晶体管
在中国做房贷,有一个全球独一无二的硬件加速器,叫住房公积金。
它是一个你每个月强制存入的长期储蓄账户,你和你的雇主按比例共同缴存。它最核心的特性是:贷款利率远低于商业贷款。商业房贷利率常年4%到5%,公积金贷款利率在3%附近,甚至更低。三十年等额本息算下来,用公积金贷款比纯商贷节省的利息,可以再买一辆不错的车。
但很多工程师对这个加速器的用法是错的。他们嫌公积金贷款审批麻烦,额度不够高,直接全走了商贷,公积金账户里的钱就躺在那里,每年拿1.5%的活期利息。然后他们把自己的税后工资拿去买年化3%的银行理财,沾沾自喜觉得自己在套利。
你不是在套利。你是在把一块专门用来做硬件解码的专用芯片闲置不用,然后让主CPU去跑软解,还洋洋得意地说“CPU占用率高了点但能跑”。
正确的用法是:公积金贷款能贷多少贷多少,贷到上限。剩下的差额部分,再用商业贷款补足。这就是组合贷。公积金贷款的每一块钱,都是你用远低于市场利率的成本获得的长期资金。你把这个长期低息资金锁定在房贷上,你的自有资金就可以释放出来,配置到收益更高的资产上去。
还有一种更隐蔽的浪费:公积金账户余额闲置。很多人不知道,公积金账户里的余额可以用来提前还贷,或者用来冲还贷。如果你的公积金账户已经攒了十几万,每年只拿1.5%的利息,而你的商业贷款那边每年在付4.5%的利息,你这中间三个点的利差,就是你为懒惰付出的代价。把这笔钱提出来冲还商业贷款本金,你不需要做任何投资决策,不需要承担任何风险,你就省掉了那三个点的利息支出。这是无风险套利,而且合法合规。
不要用中断处理长期负债:那等于用ISR跑大数据
回到本节开头那个把房贷挪去补仓的工程师。
他犯的错误,本质上是什么?
他让一个硬实时的长期任务,去依赖一个高频振荡、随机性极强的短期投机收益。他用中断服务程序去处理一个需要持续稳定运行的后台守护进程。
你写嵌入式代码的时候有一个铁律:中断处理程序必须极短。ISR里不能做复杂计算,不能做阻塞调用,不能分配大块内存,不能做任何不确定执行时间的操作。为什么?因为ISR运行时,CPU屏蔽了其他同级和低级中断。你在ISR里多耗一毫秒,整个系统的实时响应就退化一毫秒。你如果在ISR里跑一个需要三秒钟才能完成的数据处理,这三秒内所有的中断请求全部被丢弃,系统处于假死状态。
你用来还房贷的钱,就是内核层和系统服务层的任务。它应该由工资、租金、固收利息这些稳定输出的信号源来驱动。它是一个后台守护进程,不急不躁,按部就班,三十年如一日地跑完。
你用来炒股的钱,是应用层的高风险投机。它在时间尺度上是完全不同的东西——它可以一天内上下波动20%,可以连续涨停三天然后跌停五天,可以被停牌锁死半年。它是一个高频中断信号,时有时无,极不稳定。
你用不稳定的信号去驱动硬实时任务,就等于用ISR跑大数据。你的中断处理程序已经跑了一分钟还没结束,这期间房贷扣款这个硬中断来了,被屏蔽了。你补仓的股票还在跌,你的还款账户余额不够,扣款失败。系统故障。
从今天开始,给你的财务系统加一条不可绕过的断言:
任何用于偿还长期负债的资金,不得经过应用层。
你的月供,只能来自工资、固收利息、租金、以及其他低波动的稳态收入源。股票赚了钱,你当然可以把利润提取出来,转到还款账户里——这是合法的系统调用,从应用层向下回流。但你不能反向操作。你不能把下个月的月供先挪去股市里“周转一下”。周转这个词,在财务系统里是时序违例的同义词。
在结束本节之前,我再给你一套简短的自检标准。你可以现在就对照一下:
你的固收类资产(债券、存单、储蓄型保险)是否至少占你总资产的15%?如果没有,你缺的不是投资收益,是系统崩溃时的底层驱动。
你的房贷月供账户里,是否提前预留了至少三个月的月供余额?如果没有,你的硬实时任务在时钟停振时会立刻违约。
你有没有公积金账户?如果有,它现在是以低息活期闲置着,还是已经被最大化地用于低息贷款或冲还贷?
你有没有在过去的十二个月里,因为“机会太好”而从房贷账户里挪过钱去补仓?如果有,请在今天下午就把它还回去。这不是投资策略的失误,这是系统架构的违例。
下一节,我们往上走到应用层——你的股票、基金、Crypto该跑在什么样的沙箱里,沙箱之间如何隔离,单票仓位上限为什么必须写在代码里而不是记在心里。