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 個のアイテムをエンコードしました。しかし、実際の状況では、これはもっと多くなる可能性があります。上記のコードでは、XML の作成に約 20 秒かかりました。これは許容範囲をはるかに超えていました。何が問題なのですか?そして、ここでパフォーマンスを向上させる方法は?

注 : 文字列クラスの使用法には大きな違いはありません。MFC CString の別の文字列実装で同じロジックをテストしたところ、同様の (はるかに悪い) 観察結果が得られました。また、XML をより適切な方法で準備するために、ここでは DOM XML パーサーを使用したくありません。質問は XML に固有のものではありません。

4

2 に答える 2

0

コンテンツを作成する前に結果文字列 ( ) の長さを見積もることができればanXMLString、文字列に十分なバッファ スペースを割り当てることができます。バッファーが十分に大きい場合、(ターゲット文字列の) 再割り当てとコピーは行われません。

こちらです:

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

std::stringについてはわかりません。追加ポイントを検索する必要がありますか、それとも文字列の長さをメモリに保持しますか。

于 2012-07-09T11:52:40.057 に答える
0

問題は、同じ文字列がますます長くなるという事実が原因である可能性があることに気付きました。これにより、次の結果が得られます。1.文字列が大きくなるにつれて、文字列の連結はより高価になります。ループが進行し、ますます遅くなります。

これを解決するために、一時的な文字列を使用して個々のアイテムの 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 ミリ秒でした。

したがって、私が学んだ教訓は、より大きな結果を作成するときは、サブ操作に分割し、サブ操作の結果を新しい文字列に収集し、グローバル結果に 1 回追加するということです。これがすでにパターンなのか名前なのかはわかりません。

StackOverFlow は、Q&A の観点から経験を共有するオプションを提供したので、それを利用することを考えました。コメント/改善は大歓迎です。

于 2012-07-09T11:16:03.247 に答える