Higgs实习记录
思考
- 程序实现的时候要将代码逻辑和业务结合起来,比如说LoadParam中给定一个仓位,在db文件中查询相距最近的仓位对应的TradeParam,并不是单单去寻找唯一一个Param,那样的话一天就只会做一次交易,而是对于数据中每一个时间段都去寻找一个最近的仓位对应的TradeParam。
- 遇到非技术性问题先问deepseek,整理文档或代码时把问题整理到一起再问。
技术
多线程
线程是程序中的独立执行流,属于同一进程内的多个线程 共享进程的内存空间(如全局变量、堆内存),但每个线程拥有 独立的栈空间和执行上下文(如寄存器状态、程序计数器)。
线程 vs 进程:
特征 | 进程 | 线程 |
---|---|---|
资源分配 | 操作系统资源分配的基本单位(独立内存空间) | 进程内的执行单元(共享进程内存) |
切换开销 | 高(涉及虚拟内存、文件描述符等切换) | 低(仅切换栈和寄存器) |
创建销毁 | 通过 fork() 创建,系统调用消耗大 |
通过 pthread_create() 创建,消耗小 |
独立性 | 相互隔离,一个进程崩溃不影响其他进程 | 共享内存,一个线程崩溃可能导致整个进程终止 |
通信方式 | 管道、消息队列、共享内存、Socket 等 | 直接读写共享变量(需同步机制) |
CPU调度 | 进程是 CPU 资源分配的基本单位 | 线程是 CPU 调度的基本单位 |
数据对齐
内存对齐的核心规则
- 成员对齐规则:每个成员的起始地址必须是其自身大小的整数倍(例如
int
需4字节对齐,double
需8字节对齐)。 - 结构体填充规则:结构体总大小必须是其最大成员大小的整数倍。
- 成员顺序影响:成员顺序不同会导致填充字节的数量变化,进而影响总内存占用。
struct TestA{
char a;
int b;
char c;
double d;
};
内存布局(假设默认8字节对齐):
- char a占1字节,偏移量0。
- int b需4字节对齐,因此在a后填充3字节(偏移量4-7)。
- char c占1字节,偏移量8。
- double d需8字节对齐,因此在c后填充7字节(偏移量16-23)。
- 总大小:1+3(填充)+4+1+7(填充)+8 = 24字节。
struct TestB{
char a;
char c;
int b;
double d;
};
内存布局:
- char a和char c共占2字节,偏移量0-1。
- int b需4字节对齐,因此在c后填充2字节(偏移量4-7)。
- double d直接对齐到偏移量8(无需填充)。
- 总大小:1+1+2(填充)+4+8 = 16字节。
struct TestC{
char a;
char c;
double d;
char b;
};
内存布局:
- char a和char c共占2字节,偏移量0-1。
- double d需8字节对齐,因此在c后填充6字节(偏移量8-15)。
- char b占1字节,偏移量16。
- 结构体总大小需是最大成员double的倍数(8字节),因此在b后填充7字节。
- 总大小:1+1+6(填充)+8+1+7(填充) = 24字节。
设计模式
Impl设计模式
- 接口与实现解耦:
- 隐藏私有细节:通过将类的私有成员封装在一个独立的实现类中,头文件仅暴露公共接口,避免内部实现细节泄露。
- 降低耦合性:接口类仅持有指向实现类的指针(unique_ptr或shared_ptr),实现类的修改不会影响接口类的用户代码。
- 减少编译依赖与提升编译速度
- 最小化头文件修改影响:当实现类的内部逻辑变更时,只需重新编译实现文件(.cpp),而非所有包含原头文件的代码,显著减少大型项目的编译时间。
- 避免头文件污染:减少头文件中的依赖项(如第三方库或复杂模板),简化编译流程。
- 增强二进制兼容性
- 动态库接口稳定:在动态库开发中,接口类的内存布局不会因实现类的成员增减而改变,客户端无需重新编译即可兼容新版本。
- 资源管理与安全性
- 自动内存管理:结合智能指针(如unique_ptr),可自动释放实现类对象,避免内存泄漏。
- 防止悬垂指针:智能指针确保指针始终有效或为空,规避非法访问风险。
- 支持灵活的实现扩展
- 多态性与桥接模式:可通过替换不同的实现类(如平台相关代码),动态切换功能模块,符合开闭原则。
- 惰性初始化优化:实现类可按需初始化,提升资源利用率6。
Adapter设计模式
Adapter模式通过创建一个中间层(适配器类),将一个类的接口转换为客户端期望的另一个接口,从而解决接口不兼容的问题。其核心角色包括:
- Target(目标接口):客户端期望的接口。
- Adaptee(被适配者):需要被适配的现有类或接口。
- Adapter(适配器):将Adaptee的接口转换为Target接口的中间类 Ops Adapter包括td(trade data) adapter和md(market data) adapter,主要作用是屏蔽来自不同券商的api接口的差异,并统一适配到Higgs Ops interface定义的接口,以便于上层策略模块调用。
工厂模式
通过引入“工厂类”替代直接使用 new 关键字创建对象,将对象的创建逻辑集中管理,客户端仅需与工厂接口交互,无需关心具体类的实例化细节:
- 解耦:分离对象的创建与使用,降低模块间的依赖。
- 封装:隐藏复杂的初始化逻辑(如数据库连接、配置解析),提供统一的创建接口。
- 扩展性:支持新增产品类型时无需修改客户端代码,符合“开闭原则”。
数据结构
std::set
std::set 是基于 红黑树(一种自平衡二叉搜索树)实现的。红黑树的高度始终保持在 O(log n) 级别,因此所有基于树遍历的操作(如查找、插入、删除)的时间复杂度均为对数级别。
- 需要频繁进行范围查询(如 lower_bound、upper_bound)时,std::set 的高效查找特性非常有用。
- 若仅需判断元素是否存在,优先使用 std::unordered_set(查找时间复杂度 O(1))。
- 若使用 std::lower_bound 在已排序的 vector 中查找,时间复杂度同样是 O(log n),但需要手动保证容器有序。若 vector 无序,需先排序(O(n log n)),再使用 lower_bound。