因此,我有一个C ++程序,该程序基本上可以解析巨型数据集文件,并将内容加载到内存中的hashmap中。完成后,我将指针翻转到新的内存位置,并在旧的位置调用delete。除此之外,程序正在通过查找内存映射中的内容来进行传入请求匹配。假设这些巨型地图包装在Evaluator
类中:
Evaluator* oldEvaluator = mEvaluator;
Evaluator* newEvaluator = parseDataSet();
mEvaluator = newEvaluator;
delete oldEvaluator;
//And then on request processing:
mEvaluator.lookup(request)
该映射可以包含数百万个字符串对象,作为keys。它们是常规字符串,可以作为请求属性,如ip,UserAgent等,但每个都是插入到STL unordered_map中的字符串对象。
数据集会定期更新,但是在大多数情况下,程序只是针对内存中的数据集进行请求属性匹配,它很好且高效,并且没有错误,除非发生了新数据集的大量消耗的情况。使用这种大数据集的另一种方法是使用流式传输,但这是一个相对长期的解决方案。
它曾经是使用事件驱动模型的单线程程序,但是每次放置一个完整的新集合并调用销毁程序时,删除整个内容花费的时间太长,因此阻塞了请求处理。
所以我将删除此类映射到单独的线程上。问题是,现在删除和请求处理似乎同时发生,我可以看到请求处理线程上非常明显,急剧的减速。
当然,主机上还有其他进程正在运行,我确实希望2个线程能够竞争CPU周期。但是我没想到会看到请求匹配线程急剧下降,它变得如此之慢,以至于有时请求匹配在中间被CPU中断了几百毫秒才能完成其他工作。平均来说,一个请求应该在500us级别处理,但是在删除线程运行时,它的处理速度只有5毫秒,这在我看不到中断的情况下。有时cpu中断可能会长达50毫秒或120毫秒,等等。一个请求可能需要处理整个1000毫秒,这大约是整个数据结构删除占用另一个线程的时间。
了解这种减速的根本原因的最佳方法是什么? 是不是CPU或内存带宽瓶颈?我一直在想,只要将它放在一个单独的线程上,我就不会在乎它的运行速度,因为它毕竟必须一个一个地删除字符串对象,所以我没想到它会影响另一个线程...
EDIT:多亏了一些评论/回答,似乎已经指出了几种可能的原因:
那么我该怎么办?我尝试了Jemalloc
,但不确定是否可以完全正确地使用它---似乎在链接器行中包含-ljemalloc
只是神奇地替换了libc的malloc?我尝试时没有任何性能差异,但可能使用错误。我的程序没有执行任何显式的malloc,所有内容都是new
,大小事先未知,是的,它与指针和STL映射挂钩。
而且所有存储在Key
中的字符串都专门用于快速查找,因此即使它们会占用连续的存储空间,也无法将它们存储在带有索引的向量中,找到它们将是可怕的。因此,Jemalloc
是否解决了这两种情况)因此,我有一个C ++程序,该程序基本上可以解析巨型数据集文件,并将内容加载到内存中的hashmap中。完成后,我将指针翻转到新的内存位置,并在...
您可以尝试使用std::vector
来存储内存。 std::vector
元素是连续存储的,因此它将减少高速缓存未命中(请参阅What is a "cache-friendly" code?)
因此,您将拥有一个map<???,size_t>
而不是map<???,std::string>
,您将有一个以上的间接方式来获取您的字符串(这意味着额外的运行时成本),但它允许您以较少的缓存丢失来迭代所有字符串。
这将是一个冗长的答案,因为您的问题非常复杂。