扁平合并订单簿
Flat Combining Orderbook
题目详情
Flat Combining 是低延迟交易系统中缓解锁竞争的同步范式:线程将请求发布到线程本地记录,由合并者线程批量处理,显著减少锁获取次数和缓存行争用。
任务:实现 Flat Combining 订单簿类,使用 flat combining 更新订单簿。各线程将操作请求写入线程本地发布记录,合并者线程扫描所有记录批量执行。支持添加、取消、修改操作。
英文原题
Flat combining is a synchronization paradigm used in low-latency trading systems to mitigate lock contention by allowing threads to publish requests to thread-local records, which a single "combiner" thread processes in a batch. This technique drastically improves cache locality and reduces synchronization overhead, making it highly effective for maximizing throughput in high-frequency trading engines.
Task
Implement a simulator for a Flat Combining Order Book by completing the FlatCombiningSim
解析
问题分析
扁平合并(Flat Combining)是一种并发优化技术:多个生产者线程将请求提交到全局队列,单个合并线程批量处理并将结果返回。在订单簿场景中,这消除了对每个价格档位的锁竞争,显著提升多核吞吐量。
实现
class FlatCombiningOrderBook {
struct Request { enum {ADD, CANCEL, GET} op; uint64_t id; double price; int qty; };
std::vector<Request> reqs_[2]; // 双缓冲
std::atomic<int> active_{0};
std::mutex mtx_;
public:
void submit(Request r) {
std::lock_guard lk(mtx_);
reqs_[active_].push_back(r);
}
void combine() {
int batch = active_.exchange(1 - active_, std::memory_order_acq_rel);
for (auto& r : reqs_[batch]) {
switch (r.op) { /* 批量执行所有请求 */ }
}
reqs_[batch].clear();
}
};复杂度与边界
- 时间复杂度:combine O(批量大小),单请求均摊 O(1)
- 空间复杂度:O(最大批量大小)
- 边界条件:(1) 合并线程需定期唤醒(即使无请求)(2) 批量过大会增加单个请求延迟 (3) 请求需带序列号以正确返回结果
英文解析
Analysis
Flat Combining is a concurrency optimization technique: multiple producer threads submit requests to a global queue, and a single combiner thread processes them in batch and returns results. In order book scenarios, this eliminates lock contention on each price level, significantly improving multi-core throughput.
Solution
class FlatCombiningOrderBook {
struct Request { enum {ADD, CANCEL, GET} op; uint64_t id; double price; int qty; };
std::vector<Request> reqs_[2]; // double-buffer
std::atomic<int> active_{0};
std::mutex mtx_;
public:
void submit(Request r) {
std::lock_guard lk(mtx_);
reqs_[active_].push_back(r);
}
void combine() {
int batch = active_.exchange(1 - active_, std::memory_order_acq_rel);
for (auto& r : reqs_[batch]) {
switch (r.op) { /* batch-execute all requests */ }
}
reqs_[batch].clear();
}
};Complexity & Edge Cases
- Time complexity: O(P) for P combining participants; O(log N) for order book priority queue insertion
- Space complexity: O(N + P) for N orders and P combiner request slots
- Edge cases: (1) Combiner thread starvation if no thread wins the lock frequently. (2) Request slot overflow during burst periods. (3) Delayed execution for non-combiner threads adds latency variance.
Key Considerations
- Batch processing: Combining multiple requests into one batch reduces per-request synchronization overhead.
- Double buffering: Active buffer accepts new requests while standby buffer is being processed.
- Combiner thread: Must periodically wake up (even with no requests) to check for pending work.
- Time complexity: combine O(batch size); single request amortized O(1).