除了@jimwise提供的出色的硬件/设置调整答案之外,“低延迟linux”还意味着:
- C ++出于确定性的原因(GC启动时不会出现意外延迟),访问低级功能(I / O,信号),语言能力(充分使用TMP和STL,类型安全)。
- 首选内存速度:> 512 Gb RAM是常见的;数据库是内存中的,预先缓存的或特殊的NoSQL产品。
- 算法选择:尽可能快与理智/可理解/可扩展,例如无锁定的多位数组,而不是带有布尔属性的对象数组。
- 充分利用操作系统功能,例如不同内核上的进程之间的共享内存。
- 安全。HFT软件通常位于联合交易所中,因此无法接受恶意软件。
这些技术中有许多与游戏开发重叠,这就是金融软件行业吸收任何最近裁员的游戏程序员的原因之一(至少直到他们付了欠款为止)。
基本需求是能够侦听诸如安全性(股票,商品,外汇)价格之类的市场数据的带宽很高的流,然后根据安全性,价格做出非常快速的买/卖/不做决定。和当前持股。
当然,这全都可能出错。
因此,我将详细说明位阵列点。假设我们有一个高频交易系统,该系统可以处理大量订单(买入5k IBM,卖出10k DELL等)。假设我们需要快速确定是否所有订单都已完成,以便我们可以进行下一个任务。在传统的OO编程中,这看起来像:
class Order {
bool _isFilled;
...
public:
inline bool isFilled() const { return _isFilled; }
};
std::vector<Order> orders;
bool needToFillMore = std::any_of(orders.begin(), orders.end(),
[](const Order & o) { return !o.isFilled(); } );
该代码的算法复杂度为O(N),因为它是线性扫描。让我们看一下内存访问方面的性能概况:std :: any_of()内循环的每次迭代都将调用内联的o.isFilled(),因此成为_isFilled的内存访问(1字节) (或4个取决于您的体系结构,编译器和编译器设置)在一个总共128个字节的对象中。因此,我们每128个字节访问1个字节。假设是最坏的情况,当我们读取1个字节时,将得到CPU数据缓存未命中。这将导致对RAM的读取请求,该请求从RAM读取整行(请参阅此处以获取更多信息),仅读取8位。因此,内存访问配置文件与N成正比。
与以下内容进行比较:
const size_t ELEMS = MAX_ORDERS / sizeof (int);
unsigned int ordersFilled[ELEMS];
bool needToFillMore = std::any_of(ordersFilled, &ordersFilled[ELEMS+1],
[](int packedFilledOrders) { return !(packedOrders == 0xFFFFFFFF); }
再次假设是最坏的情况,其内存访问配置文件是ELEMS除以RAM行的宽度(变量-可能是双通道或三通道等)。
因此,实际上,我们正在优化内存访问模式的算法。RAM数量无济于事-导致此需求的是CPU数据缓存大小。
这有帮助吗?
YouTube上有出色的CPPCon演讲,内容涉及低延迟编程(适用于HFT):https : //www.youtube.com/watch?v= NH1Tta7purM