1

GUI のテキスト ボックスBackgroundWorkerを使用してメッセージを投稿するスレッドがあります。テキスト ボックスにテキストを表示するBeginInvokeメソッド は、 を使用し、テキストを に書き込みます。 write_debug_textAppendTextConsole

BackgroundWorker書き込み速度が速すぎて、write_debug_textが追いついていないようです。ブレークポイントを設定し、write_debug_textヒットするまで長い時間待たなければなりません。ブレークポイントに到達する前に、BeginInvoke の呼び出しが多数発生します。

System.ConsoleVS C# Express IDE のように、UI にメッセージをリアルタイムで表示する方法を探しています。

SO での検索から、それAppendTextが使用するより高速な方法であり、文字列を再割り当てする必要がある場合があることを理解しています。

一部の返信はStringBuilder、そのテキストをテキストボックスに定期的に書き込むことを提案しています。ただし、これにはさらにイベントとタイマーを追加する必要があります。私はむしろやりたくないことです (私の単純なアプリケーションはますます複雑になっています)。

テキストボックスにリアルタイムで書き込む (そして表示させる) にはどうすればよいですか?

私の現在の考えは、テキスト キューとタイマーを使用する Textbox から継承するウィジェットを作成することです。

編集 1: サンプル コード

ここに私のコードの断片があります:

    private m_textbox;
    //...
    m_textbox.BeginInvoke(new write_debug_text_callback(this.write_debug_text),
                                      new object[] { debug_text });
    return;

private void write_debug_text(string text)
{
    string time_stamp_text = "";
    time_stamp_text = DateTime.Now.ToString() + "   ";
    time_stamp_text += text;
    m_textbox.AppendText(time_stamp_text);
    m_textbox.Update();
    System.Console.Write(time_stamp_text);
    return;
}

に変更しようとしBeginInvokeましたがInvoke、アプリケーションがハングしました。デバッガーを使用して一時停止/中断すると、実行ポインターは への呼び出しにありInvokeます。

ところで、私は Java、C++、および C で長年の経験があります。C# を使用して 5 か月目です。

4

6 に答える 6

1

表示されているメッセージが非常に多い場合、問題はメモリ割り当ての問題である可能性があります。

各メッセージの長さが30文字であると仮定しましょう。これは(おおよそ)60バイトになります。さらに、1秒あたり10個のメッセージを追加するとします。次に、最初の1秒間に、生成される文字列は60 + 120 + 60 + 180 + 60 + 240 + 60 + 300 + ... + 60 + 600=3840バイトになります。2秒目に、合計は13,740バイトに増加します。3秒目:29,640。4位:51,540。... 10番目:308,940バイト。

18秒後、1メガバイトに達し、表示される文字列はそれぞれ11kbです。

1分の時点で、10Mbの文字列が割り当てられています。2分で43Mbがこれらのメッセージに費やされ、文字列サイズはそれぞれ71kbずつ増加します。3分後、メッセージのサイズは100 kbを超え、100Mb近くがメッセージに割り当てられます。

これが、StringBuilderが長い文字列を作成するために非常に重要である理由です。

ただし、各中間ステップを表示することを計画しているため、StringBuilderはここでは役に立ちません。このGUIでは、メートル法のボート負荷の文字列を生成する必要があります。

この問題の1つの可能な解決策は、データを後ろに挿入するときに文字列の前を切り落とすことです。引き続き多くのメモリを文字列に割り当てますが、個々の文字列自体のサイズは制限されているため、ランタイムがメモリ内でそれらの場所を見つけるのがはるかに簡単になり、割り当て率は同様に下に行きます。

これにより、ガベージコレクションのプレッシャーが軽減されます。

private const int maxDisplayTextLength = 5000;

private void write_debug_text(string text)
{
    string time_stamp_text = "";
    time_stamp_text = DateTime.Now.ToString() + "   " + text;
    string previous = m_textbox.Text;
    if (previous.Length + time_stamp_text.Length > maxDisplayTextLength)
         m_textbox.Text = previous.Substring(0, maxDisplayTextLength - time_stamp_text.Length) + time_stamp_text;
    else
         m_textbox.Text = previous + time_stamp_text;
    m_textbox.Update();
    System.Console.Write(time_stamp_text);
    return;
} 
于 2011-03-30T19:55:33.840 に答える
1

多分http://sourceforge.net/projects/fastlogconsoleを試してください-優れたパフォーマンスがあります

于 2012-09-13T12:21:39.693 に答える
0

テキストボックス内でリアルタイムの書き込みが必要な場合は、後で呼び出される関数をキューに入れるInvoke代わりに、同期を使用しないのはなぜですか?BeginInvoke

于 2011-03-30T18:52:16.860 に答える
0

使用しないでくださいBeginInvokeInvoke代わりに使用してください。数千行の追加中にアプリケーションが応答しなくなるを参照してください。それはまったく同じ問題ではありません (彼はテキスト ボックスではなく DataGridView を使用しています) が、同じ種類のものです。大量の非同期BackgroundWorkerタスクを開始しています。一度に 1 つずつ実行する方がよいでしょう。

于 2011-03-30T18:52:56.643 に答える
0

代わりにコントロールを使用してみて、RichTextBoxときどき例外を除いて UI を更新しないようにすることができます。提案に似てStringBuilderいますが、もう少し単純です。その方法の例については、このSO の質問を参照してください。

于 2011-03-30T18:54:45.083 に答える
0

@Jeffre L. Whitledge のアドバイスを使用して、文字列割り当ての数を減らしました。これは固定数の文字列を持つクローズド アプリケーションであるため、文字列をキャッシュしました。これにより、プログラムの実行が大幅に高速化されるという副作用が生じました。

私の問題の 1 つは、メッセージへの Windows の応答が依然として遅いことです。これは、プログレス バーが更新されたときに確認できます。メッセージが送信されてから (テキストの追加など)、実行されるまでには明確な遅延があります。

于 2011-05-14T21:53:52.257 に答える