0

結果が何であるかに応じて、返された結果セットを特定の方法で色分けするプログラムがあります。結果を色分けするのに時間がかかるため (現在は Regex と RichTextBox.Select + .SelectionColor で行っています)、400 件の結果で色分けを切り捨てました。その数のあたりで、約 20 秒かかります。これは、私が妥当と考える最大時間です。

Parallel.ForEachパフォーマンスの向上を試みるために、ループを使用して を反復処理するように Regex 部分を書き直しましMatchCollectionたが、時間はほぼ同じでした (18 ~ 19 秒対 20 秒)。並列プログラミングに非常に適した仕事ではありませんか? 何か違うことを試す必要がありますか?どんなアドバイスでも大歓迎です。ありがとう!

PS: Parallel.ForEach の有無にかかわらず、私の CPU 使用率が約 14% にならないのは少し奇妙だと思いました。

コード

MatchCollection startMatches = Regex.Matches(tempRTB.Text, startPattern);

object locker = new object();
System.Threading.Tasks.Parallel.ForEach(startMatches.Cast<Match>(), m =>
{
    int i = 0;
    foreach (Group g in m.Groups)
    {
        if (i > 0 && i < 5 && g.Length > 0)
        {
            tempRTB.Invoke(new Func<bool>(
                delegate
                {
                    lock (locker)
                    {
                        tempRTB.Select(g.Index, g.Length);
                        if ((i & 1) == 0) // Even number
                            tempRTB.SelectionColor = Namespace.Properties.Settings.Default.ValueColor;
                        else              // Odd number
                            tempRTB.SelectionColor = Namespace.Properties.Settings.Default.AttributeColor;
                        return true;
                    }
                }));
        }
        else if (i == 5 && g.Length > 0)
        {
            var result = tempRTB.Invoke(new Func<string>(
                delegate
                {
                    lock (locker)
                    {
                        return tempRTB.Text.Substring(g.Index, g.Length);
                    }
                }));

            MatchCollection subMatches = Regex.Matches((string)result, pattern);

            foreach (Match subMatch in subMatches)
            {
                int j = 0;
                foreach (Group subGroup in subMatch.Groups)
                {
                    if (j > 0 && subGroup.Length > 0)
                    {
                        tempRTB.Invoke(new Func<bool>(
                            delegate
                            {
                                lock (locker)
                                {
                                    tempRTB.Select(g.Index + subGroup.Index, subGroup.Length);
                                    if ((j & 1) == 0) // Even number
                                        tempRTB.SelectionColor = Namespace.Properties.Settings.Default.ValueColor;
                                    else              // Odd number
                                        tempRTB.SelectionColor = Namespace.Properties.Settings.Default.AttributeColor;
                                    return true;
                                }
                            }));
                    }
                    j++;
                }
            }
        }
        i++;
    }
});
4

2 に答える 2

4

コードで最も多くの時間を費やしているのは、リッチテキスト ボックス内のテキストを実際に選択して色を設定する部分です。

このコードは、UI スレッドにマーシャリングする必要があるため、並行して実行することはできませんtempRTB.Invoke

lockさらに、ステートメントを使用して、強調表示が並列ではなく順次実行されることを明示的に確認します。とにかく、そのコードはすべて単一の UI スレッドで実行されるため、これは不要です。


RTB でテキストを選択して色を付ける間、UI のレイアウトを一時停止することで、パフォーマンスを向上させることができます。

tempRTB.SuspendLayout();

// your loop

tempRTB.ResumeLayout();
于 2013-05-14T14:34:53.420 に答える
4

実際には、プログラムのどの側面も実際に並行して実行することはできません。

一致の生成は、順番に行う必要があります。最初の一致が見つかるまで、2 番目の一致は見つかりません。 Parallel.ForEachせいぜい、シーケンスの結果を並行して処理できるようになりますが、それでも順次生成されます。これは、時間のかかる作業の大部分が行われているように思われる場所であり、そこには何のメリットもありません。

その上、実際には結果を並行して処理していません。ループの本体で実行されるコードの大部分はすべて、UI スレッドへの呼び出し内にあります。つまり、すべてが単一のスレッドによって実行されます。

要するに、プログラムのごく一部だけが実際に並列実行され、並列化を使用すると一般にオーバーヘッドがいくらか追加されます。そのオーバーヘッド以上のものをかろうじて得ているように思えます。正規表現が個別に (並列で) 解析できるいくつかの小さなチャックに初期文字列を分割する効果的な方法がない限り、操作は本質的に並列化に適していません

于 2013-05-14T14:35:00.660 に答える