0

最近,我们遇到了一段生成 XML 的代码的性能问题。想在这里分享经验。这有点长,请多多包涵。

我们准备了一个包含许多项目的简单 XML。每个项目可以有 5-10 个元素。结构是这样的:

<Root>
    <Item>
        <Element1Key>Element1Val</Element1Key>
        <Element2Key>Element2Val</Element2Key>
        <Element3Key>Element3Val</Element3Key>
        <Element4Key>Element4Val</Element4Key>
        <Element5Key>Element5Val</Element5Key>
    <Item>
    <Item>
        <Element1Key>Element1Val</Element1Key>
        <Element2Key>Element2Val</Element2Key>
        <Element3Key>Element3Val</Element3Key>
        <Element4Key>Element4Val</Element4Key>
        <Element5Key>Element5Val</Element5Key>
    <Item>
</Root>

生成 XML 的代码是(简化为全局函数):

void addElement(std::string& aStr_inout, const std::string& aKey_in, const std::string& aValue_in)
{
    aStr_inout += "<";
    aStr_inout += aKey_in;
    aStr_inout += ">";
    aStr_inout += "Elemem1Val";
    aStr_inout += "<";
    aStr_inout += aValue_in;
    aStr_inout += ">";
}

void PrepareXML_Original()
{
    clock_t commence,complete;
    commence=clock();

    std::string anXMLString;
    anXMLString += "<Root>";

    for(int i = 0; i < 200; i++)
    {
        anXMLString += "<Item>";
        addElement(anXMLString, "Elemem1Key", "Elemem1Value");
        addElement(anXMLString, "Elemem2Key", "Elemem2Value");
        addElement(anXMLString, "Elemem3Key", "Elemem3Value");
        addElement(anXMLString, "Elemem4Key", "Elemem4Value");
        addElement(anXMLString, "Elemem5Key", "Elemem5Value");
        anXMLString += "</Item>";


        replaceAll(anXMLString, "&", "&amp;");
        replaceAll(anXMLString, "'", "&apos;");
        replaceAll(anXMLString, "\"", "&quot;");
        replaceAll(anXMLString, "<", "&lt;");
        replaceAll(anXMLString, ">", "&gt;");
    }
    anXMLString += "</Root>";

    complete=clock();
    LONG lTime=(complete-commence);
    std::cout << "Time taken for the operation is :"<< lTime << std::endl;
}

replaceAll() 代码将用编码形式替换特殊字符。这在下面给出。

void replaceAll(std::string& str, const std::string& from, const std::string& to) 
{
    size_t start_pos = 0;
    while((start_pos = str.find(from, start_pos)) != std::string::npos) 
    {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length();
    }
}

在最小的例子中,我编码了 200 个项目。但是,在实际情况下,这可能更多。上面的代码花费了大约 20 秒来创建 XML。这远远超出了任何可接受的限度。可能是什么问题呢?以及如何提高这里的性能?

注意:字符串类的用法没有太大区别。我用 MFC CString 的另一个字符串实现测试了相同的逻辑,我得到了类似(更糟)的观察结果。另外,我不想在这里使用任何 DOM XML 解析器来以更好的方式准备 XML。这个问题并不特定于 XML。

4

2 回答 2

0

我意识到问题可能是由于相同的字符串越来越长,这导致以下结果:1.随着字符串的增长,字符串连接变得更加昂贵 2.字符替换发生在更大的字符串中循环继续进行并且变得越来越慢。

为了解决这个问题,我使用了一个临时字符串来对单个项目 XML 进行编码,并在循环结束时将这个小 XML 附加到主 XML 中。修改后的方法如下。

for(int i = 0; i < 200; i++)
{
    std::string anItemString;  // Create a new string for the individual Item entry
    anItemString += "<Item>";
    addElement(anItemString, "Elemem1Key", "Elemem1Value");
    addElement(anItemString, "Elemem2Key", "Elemem2Value");
    addElement(anItemString, "Elemem3Key", "Elemem3Value");
    addElement(anItemString, "Elemem4Key", "Elemem4Value");
    addElement(anItemString, "Elemem5Key", "Elemem5Value");
    anItemString += "</Item>";


    replaceAll(anItemString, "&", "&amp;");
    replaceAll(anItemString, "'", "&apos;");
    replaceAll(anItemString, "\"", "&quot;");
    replaceAll(anItemString, "<", "&lt;");
    replaceAll(anItemString, ">", "&gt;");

    anXMLString += anItemString;   // Do all the operations on the new string and finally append to the main string.
}

这提高了 XML 创建的性能,所用时间仅为 17 毫秒!

因此,我学到的教训是,在创建更大的结果时,将其拆分为子操作,将子操作的结果收集到新字符串中,并将一次附加到全局结果中。我不确定这是否已经是一种模式或名称。

由于 StackOverFlow 提供了一个选项来分享 Q&A 方面的经验,所以我想利用它。欢迎任何意见/改进。

于 2012-07-09T11:16:03.247 回答
0

如果您可以在创建内容之前估计结果字符串 ( anXMLString) 的长度,那么您可以为字符串分配足够的缓冲区空间。当缓冲区足够大时,将不会发生重新分配和复制(目标字符串)。

这边走:

std::string anXMLString;
anXMLString.reserve( size );

我不确定std :: string,它是否需要搜索附加点,或者是否将字符串的长度保留在内存中。

于 2012-07-09T11:52:40.057 回答