返回第九十章 七千万次的小石头  这个学霸疑似巨额知识来源不明首页

关灯 护眼     字体:

上一页 目录 下一页

 真正的瓶颈浮出水面。

    在调用栈里吞掉最多墙钟时间的怪物,不是那些几百万行的大矩阵乘法。

    不是复杂的HDF5文档读取,不是前端喧染的图表生成,也不是某个玄学的机器学习复杂模型。

    而是几个小得近乎不起眼的动作:排序、排名、分桶。

    在量化回测中,经常需要在特定的行业特定的市值区间内,对股票的因子暴露值进行中性化和排序。

    每次参与排序的股票可能不多,只有五个、八个、或者十六个。

    单独看,给五个数排序,不管用什么算法,每一次都快得象没有成本,连一毫秒都不需要。

    但问题在于乘数效应。

    QF-OLDLIB-001里有四百多个因子。

    三年历史版本。

    多个动态调整的样本池。

    多种回测配置。

    每一天,每一个行业,每一个状态标记、每一个数据版本,都要切出一层层的横截面进行分组排名。

    于是,这些微小的小动作被嵌套在庞大的循环网里,被反复调用。

    江临把调用栈里耗时最高的那个函数次数打印了出来

    七千八百四十二万一千九百零六次。。

    真正拖慢整个复杂系统的,从来都不是偶尔出现的大山,而是每天必须被搬运七千万次的小石头。

    写完这句话,他停顿了一下。

    为了让将来可能接手这份审计报告的平庸工程师也能看懂,他又补了一段更通俗的解释。

    一次给五张试卷按分数从高到低排序,对任何人都不难。

    难的是,系统要求你一天之内,把给五张试卷排序这个动作,重复七千万次。

    标准库里的排序算法在计算机科学上被证明是非常优秀的。

    但它们优秀的前提是通用。

    标准库就象是一套占地几万平方米的大型自动化物流分拣中心。

    它可以处理一万张试卷。

    可以处理一百万个包裹。

    可以处理带有各种奇怪对象的复杂数据结构。

    它强大,通用,绝对可靠。

    但如果你的流水在线,每次送过来的永远只有五个小包裹,而且每天要送七千万次。

    那么,你每一次都去激活那套耗电巨大的大型物流中心,让传送带空转,让机械臂寻址,去执行庞大的分拣逻辑,

    这就是不可饶恕的浪费。

    在底层代码的视角里,这种浪费体现为,为了通用性而保留的复杂的函数调用开销。

    为了处理多态而进行的动态类型检查。

    为了兼容不同数组长度,标准流程里保留了大量条件分支。

    而这些分支一旦在热点循环里反复触发,就会拖慢现代CPU最依赖的指令流水线。

    事实上,并不是系统不会排。

    而是流程太重了。

    重到CPU的每一个时钟周期都在被无意义的管理逻辑消耗。

    江临现在要做的,不是去推翻高德纳在《电脑程序设计艺术》里写下的经典排序理论,也不是发明什么震惊世界的新算法。

    他只是需要一套固定手势。

    五张试卷。

    看第一张和第二张。

    谁大谁在前面,该换就换。

    再看第三张和第四张。

    该换就换。

    几步极其固定的比较之后,顺序自然就出来了。

    不问多馀的类型问题。

    不打开多馀的内存分配流程。

    不为那根本不存在的一百万张试卷准备任何冗馀的边界检查工具。

    没有数据相关的循环,没有运行时临时选择路径。

    比较顺序在编译前就被钉死,剩下的只是固定位置之间的比较与交换。

    只处理这五个位置的数字。

    这就是在高性能计算领域里,针对极其明确边界的小规模数据,进行优化的内核奥义。

    凌晨一点二十,万籁俱寂,江临在新建的C语言扩展文档里,写下了第一版函数的签名。

    函数名很丑,甚至不象一个优雅算法库里的东西。

    它不试图排序世界上一切数组,只处理五个float64因子暴露值,五个有效性标记,以及五个原始位置编号。

    输出的也不是一个漂亮的新数组,而是一组业务排名和一组sk。

    它就象一把在废土车间里,为了拧某种特定型号引擎底盘上的特定螺丝,而被强行把手柄焊弯的怪异扳手。

    但江临现在需要的,正是这种专一暴力的扳手。

    第一版写完,江临并没有急着
本章未完,请点击下一页继续阅读>>

『加入书签,方便阅读』

上一页 目录 下一页