0

バックグラウンドワーカースレッドを無限ループで実行し、TXTファイル内の最新のエントリをチェックするログテーリングアプリがあります。新しいエントリが見つかったら、Dispatcher.Invokeを使用して、画面上のTextBoxを更新し、最新のエントリをテキストファイルに追加します。

問題は、ソーステキストファイルがミリ秒ごとに絶えず更新されている場合、Dispatcher.InvokeがTextboxを頻繁に更新しているため、ユーザーインターフェイスがフリーズしていることです。

回避策があるかどうか疑問に思います。テキストファイルからより大きなチャンクを取得することはできますが、ログテーリングのリアルタイムエクスペリエンスを台無しにしたくありません。また、UIスレッドによるTextBoxへの行の書き込みを遅らせたくありません。これにより、アプリケーションが内部の実際のデータと同期しなくなります。ソーステキストファイル。

これがバックグラウンドワーカーのDoWorkメソッドです

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
  reader = new StreamReader(new FileStream(file.File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
  lastMaxOffset = reader.BaseStream.Length;

  while (true)
  {
    if (worker.CancellationPending)
    {
      e.Cancel = true;
      break;
    }                

    if (reader.BaseStream.Length == lastMaxOffset)
      continue;

    reader.BaseStream.Seek(lastMaxOffset, SeekOrigin.Begin);

    string line = "";
    while ((line = reader.ReadLine()) != null)

    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() =>
    {
      textLog.Text += "\r" + line;
      scrollViewer.ScrollToBottom();
    })); 

    lastMaxOffset = reader.BaseStream.Position;        
  }
}

ご覧のとおり、UIスレッドは、テキストボックスにテキストを追加するだけで、頻繁にインターフェイスがフリーズすることがあります。

4

4 に答える 4

10

使用は同期呼び出しであるため、UIが要求されたタスクを実行するまでブロックDispatcher.Invokeを呼び出すため、UIスレッドでこれを行うのと実質的に同じです。Invoke短期間でそれをやりすぎると、UIスレッドが効果的にブロックされます。

代わりにDispatcher.BeginInvoke、UIスレッドが実行する作業をキューに入れるが、ブロックしないものを使用する必要があります。これはわずかに良くなります。短期間にこれをやりすぎたとしても、UIスレッドを実行するための作業で溢れかえり、その作業に多くの時間を費やすことになります。

代わりに、UIスレッドへの変更をキューに入れ、キューが定義された制限(つまり、100行の新しいテキスト)に達したとき、または特定の時間(たとえば、200ミリ秒)を超えたときに、呼び出しDispatcher.BeginInvokeて送信するのが最善の方法です。 UIへのそれらの変更。これにより、最高のUI応答性が得られます。

于 2012-06-14T17:40:24.047 に答える
1

読み取るすべての行に対して呼び出すことDispatcher.Invokeで、事実上、各行がデータを UI スレッドにプッシュし、完了するのを待ちます。

これにより、UI スレッドを直接使用するよりもルーチン全体が遅くなる可能性があります。これは、オーバーヘッドが追加されますが、作業の大部分がバックグラウンド スレッドに引き込まれないためです。

この速度を上げるには、データをバッファリングして、より大きなチャンクで送信する必要があります。この場合、新しいログ エントリを探しているので、ファイルの最後にあるすべてのログ エントリを一度に読み取り、チャンク全体を UI にマーシャリングすることをお勧めします (行ごとに行うのではなく)。 )。

于 2012-06-14T17:37:43.097 に答える
1

申し訳ありませんが、無限ループでファイルを読み取ることは誤りであり、...まあ...ばかげています。FileSystemWatcherのような明確に定義されたクラスがあり、ファイルをリアルタイムで更新したいという理由だけで CPU コアに 100% の負荷をかける必要はありません。

あなたはプログラミングにまったく慣れていないと思います-まあ、私たちは皆間違いを犯し、学ぶ必要があり、次のアドバイスを受け入れます:

  • 無限ループは自動的にプログラミングミスです
  • ループが本当に必要な場合は、反復ごとに対応するスレッドをスリープ状態にすることをお勧めします。
于 2013-01-13T12:54:59.340 に答える