【问题标题】:MSXML XSL Transformation multithreaded performance contentionMSXML XSL 转换多线程性能争用
【发布时间】:2008-11-28 19:09:39
【问题描述】:

我有一个多线程服务器 C++ 程序,它使用 MSXML6 并不断解析 XML 消息,然后应用准备好的 XSLT 转换来生成文本。我在具有 4 个 CPU 的服务器上运行它。每个线程都是完全独立的,并使用自己的变换对象。线程之间不共享任何 COM 对象。

这很好用,但问题在于可扩展性。运行时:

  1. 使用一个线程,每个线程每秒可进行大约 26 次解析+转换。
  2. 使用 2 个线程,我得到大约 20/s/线程,
  3. 具有 3 个线程,18/s/线程。
  4. 有 4 个线程,15/s/线程。

由于线程之间没有共享任何内容,我期望接近线性的可扩展性,因此 4 个线程应该比 1 个线程快 4 倍。相反,它只快 2.3 倍。

这看起来像是一个经典的争用问题。我编写了测试程序来消除我的代码中存在争用的可能性。我正在使用 DOMDocument60 类而不是 FreeThreadedDOMDocument 类,以避免不必要的锁定,因为文档永远不会在线程之间共享。我努力寻找缓存行错误共享的任何证据,但至少在我的代码中没有。

另一个线索,每个线程的上下文切换速率 > 15k/s。 我猜罪魁祸首是 COM 内存管理器或 MSXML 中的内存管理器。也许它有一个全局锁,必须为每个内存分配/释放获取和释放。我简直不敢相信,在这个时代,内存管理器的编写方式并不能很好地适应多线程多 CPU 场景。

有谁知道是什么导致了这种争用或如何消除它?

【问题讨论】:

    标签: multithreading xslt msxml contention


    【解决方案1】:

    基于堆的内存管理器(您的基本 malloc/free)使用单个互斥锁是相当普遍的,这有相当充分的理由:堆内存区域是一个单一的连贯数据结构。

    有一些替代的内存管理策略(例如分层分配器)没有这个限制。您应该研究自定义 MSXML 使用的分配器。

    或者,您应该研究从多线程体系结构迁移到多进程体系结构,每个 MSXML 工作程序都有单独的进程。由于您的 MSXML 工作者将字符串数据作为输入和输出,因此您没有序列化问题。

    总而言之:使用多进程架构,它更适合您的问题,并且可以更好地扩展。

    【讨论】:

      【解决方案2】:

      MSXML 使用 BSTR,它在其堆管理中使用全局锁。几年前,它给我们的大型多用户应用程序带来了很多麻烦。

      我们在应用程序中删除了对 XML 的使用,您可能无法执行此操作,因此您最好使用替代 XML 解析器。

      【讨论】:

        【解决方案3】:

        感谢您的回答。我最终混合了这两个建议。

        我用 C# 制作了一个 COM+ ServicedComponent,将它作为一个单独的服务器进程托管在 COM+ 下,并使用 XSLCompiledTransform 来运行转换。 C++ 服务器使用 COM 连接到这个外部进程,并将 XML 发送给它,然后取回转换后的字符串。这使性能翻了一番。

        【讨论】:

          猜你喜欢
          • 2012-05-24
          • 1970-01-01
          • 2011-12-11
          • 1970-01-01
          • 2012-09-01
          • 1970-01-01
          • 2010-12-01
          相关资源
          最近更新 更多