我有一个多线程服务器C ++程序,它使用MSXML6并连续解析XML消息,然后应用准备好的XSLT转换来生成文本。我在一个有4个CPU的服务器上运行它。每个线程都是完全独立的,并使用自己的变换对象。线程之间没有共享任何COM对象。
这很有效,但问题是可扩展性。运行时:
线程之间没有任何共享,我期望接近线性可扩展性,因此4个线程的速度应该比1快1倍。相反,它只快了2.3倍。
它看起来像是一个经典的争用问题。我编写了测试程序,以消除争议在我的代码中的可能性。我使用DOMDocument60类而不是FreeThreadedDOMDocument类,以避免不必要的锁定,因为文档永远不会在线程之间共享。我很难看到缓存行错误共享的任何证据,至少在我的代码中没有任何证据。
另一个线索,上下文切换率是>每个线程15k / s。 我猜测罪魁祸首是MSXML中的COM内存管理器或内存管理器。也许它有一个全局锁,必须为每个内存分配/释放获取和释放。我无法相信在这个时代,内存管理器的编写方式不能在多线程多CPU场景中很好地扩展。
有没有人知道是什么导致了这种争论或如何消除它?
答案 0 :(得分:2)
基于堆的内存管理器(您的基本malloc / free)使用单个互斥锁是相当常见的,它有相当好的理由:堆内存区域是一个连贯的数据结构。
存在没有此限制的备用内存管理策略(例如,分层分配器)。您应该调查自定义MSXML使用的分配器。
或者,您应该研究从多线程体系结构转向多进程体系结构,每个MSXML工作者都有单独的进程。由于您的MSXML工作者将字符串数据作为输入和输出,因此您没有序列化问题。
总结:使用多进程架构,它更适合您的问题,并且可以更好地扩展。
答案 1 :(得分:1)
MSXML使用BSTR,它在堆管理中使用全局锁。几年前,它为一个大型多用户应用程序带来了很多麻烦。
我们在应用中删除了对XML的使用,您可能无法执行此操作,因此您可能最好使用其他XML解析器。
答案 2 :(得分:1)
感谢您的回答。我最终实现了两个建议的混合。
我在C#中创建了一个COM + ServicedComponent,在COM +下将其托管为一个单独的服务器进程,并使用XSLCompiledTransform来运行转换。 C ++服务器使用COM连接到此外部进程,并将其发送给XML并获取转换后的字符串。这使性能翻了一番。