某量化开发一面
1. 实习经历与项目细节(工程实践)
- 背景调查: 你实习的公司是什么性质的机构?主要业务是什么?
- 职责确认: 在行情订阅项目中,你是从头开发的还是在原有基础上修改的?
- 量化指标考察:
- 你处理的“海量行情数据”具体的量化指标是多少?(如:每小时多少合约、数据频率是秒级还是毫秒级、CSV文件具体多大?)
- 行情订阅的性能你是如何评估的?有没有具体的判断标准?
- 优化意识:
- 在内存使用上你做了哪些优化?(如:对象池、减少内存申请销毁)。
- 当发现转换一个文件需要半小时时,你有没有分析过耗时分布?有没有尝试优化?
- 写入文件时是一次写一列还是一个数?具体的写入逻辑是怎样的?
2. 技术测试与Debug能力
遇到最难的bug
3. C++ 底层基础
- 虚函数开销: 使用虚函数除了增加虚函数表(vtable)和虚指针(vptr)的内存开销外,在调用时会有什么额外开销?
- 构造函数与多态: 在基类的构造函数中调用虚函数,会表现出多态特性吗?为什么?
4. 业务逻辑与算法
- 场景算法题(最大回撤):
- 定义: 在一段价格序列中,找到两个时间点(先高后低),使得价格下降幅度最大。
- 要求: 设计一个算法计算最大回撤率,要求时间复杂度尽可能低。
虚函数开销
1. 空间开销 (Memory Overhead)
这是最直观的开销,分为类级别和对象级别:
- 类级别 (vtable): 每个包含虚函数的类都会生成一个虚函数表(vtable),本质上是一个指针数组,存储着该类所有虚函数的地址。
- 对象级别 (vptr): 每个该类的实例对象,其内存布局的首部(或尾部)会多出一个虚函数表指针(vptr)。
- 在 64 位系统下,每个对象增加 8 字节。
- 如果对象本身很小(例如只是封装了一个 int),虚指针会使对象体积翻倍甚至更多,降低了 L1 Cache 的缓存行(Cache Line)利用率。
2. 时间开销 (Execution/Latency)
调用虚函数比普通函数慢,主要多了几次内存寻址操作:
- 第一步: 获取对象的地址,找到 vptr(一次内存访问)。
- 第二步: 通过 vptr 找到 vtable 的起始地址(一次内存访问)。
- 第三步: 在 vtable 中根据偏移量找到目标函数的真实地址(一次内存访问)。
- 第四步: 跳转到该地址执行代码(间接跳转)。
对比: 普通函数调用是直接 call
,地址在编译期就确定了;而虚函数是间接调用(Indirect Call)。3. 编译器优化开销 (Optimization Inhibitor) —— 最严重的开销
在量化高频交易中,这是最致命的。虚函数会阻止编译器进行“内联优化(Inlining)”。
- 内联失效: 内联是将函数体直接替换到调用处,消除函数调用开销(压栈、跳转、返回)。由于虚函数要在运行时才能确定调哪个,编译器在编译期不敢对其进行内联。
- 连锁反应: 函数无法内联,编译器就无法进行后续的跨函数优化,如常量折叠(Constant Folding)、死代码删除(Dead Code Elimination)等。
#发面经攒人品#HFT 视角: 如果一个函数只有 2-3 行代码,调用它的开销可能比执行它本身的开销还要大。虚函数硬生生地切断了编译器的优化链路。