2009-10-10 14 views
5

DispatcherTimerを使用してクロックティックを更新するWPFアプリケーションがあります。DispatcherTimerが時間の経過とともにCPUを消費して、WPFビジュアルが正しくレンダリングされないのを引き起こします。

しかし、アプリケーションを約6時間実行しても、時計の針の角度は変更されなくなりました。私は、DispatcherTimerがまだDebugを使って起動していること、そして角度値がまだ更新されていることを確認しましたが、スクリーンレンダリングは変更を反映しません。

また、WPFPerfツールを使用して、ラベルなし時間、目盛り(Time Manager)、AnimatedRenderMessageHandler(Media Content)がすべてCPUの約80%を消費するまで徐々に増加していることを確認しました。

hHandRT.Angleは、このコードは、直進走行の約5時間のために完璧に動作しますが、それは遅延し、角度変化が画面にレンダリングされません。その後

hHandRT = new RotateTransform(_hAngle); 

RotateTransform

への参照です。この問題のトラブルシューティング方法や可能性のある解決策の提案。

.NET 3.5、Windows VistaのSP1またはWindows XP SP3(両方が同じ挙動を示す)

EDIT:クロックティック機能にあまりで起こっての線に沿って

//In Constructor 
... 
_dt = new DispatcherTimer(); 
_dt.Interval = new TimeSpan(0, 0, 1); 
_dt.Tick += new EventHandler(Clock_Tick); 
... 

private void Clock_Tick(object sender, EventArgs e) 
     { 

      DateTime startTime = DateTime.UtcNow; 
      TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(_timeZoneId); 
      _now = TimeZoneInfo.ConvertTime(startTime, TimeZoneInfo.Utc, tst); 
      int hoursInMinutes = _now.Hour * 60 + _now.Minute; 
      int minutesInSeconds = _now.Minute * 60 + _now.Second; 
      _hAngle = (double)hoursInMinutes * 360/720; 
      _mAngle = (double)minutesInSeconds * 360/3600; 
      _sAngle = (double)_now.Second * 360/60; 
      // Use _sAngle to showcase more movement during Testing. 
      //hHandRT.Angle = _sAngle; 
      hHandRT.Angle = _hAngle; 
      mHandRT.Angle = _mAngle; 
      sHandRT.Angle = _sAngle; 

      //DSEffect 
      // Add Shadows to Hands creating a UNIFORM light 
      //hands.Effect = textDropShadow; 
     } 

を追加しますクロックティック、私は現在、この調整が役立つかどうかを確認しようとしています。バグが顕在化するために:(

//DateTime startTime = DateTime.UtcNow; 
    //TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(_timeZoneId); 
    //_now = TimeZoneInfo.ConvertTime(startTime, TimeZoneInfo.Utc, tst); 
    _now = _now.AddSeconds(1); 
+0

私は答えは分かりませんが、それは興味深い問題です。私はいくつかの答えを見ることを楽しみにしています。 –

+0

ディスパッチャータイマーにはどのくらいの頻度でチェックを入れますか? –

+0

@Greg今もその部分を追加しました。毎秒更新されます。 – discorax

答えて

4

Clockクラスは毎回ですか?.NETのタイマーは自分自身をガーベジコレクションから保護するために自分自身を根絶します。自分で停止するまでは起動し続けます。タイマーで参照されるため、Clockオブジェクトは生き続けるでしょうckイベント。

私は起きていることは、各時計で別のタイマーを始めることです。最初は1秒間に1つのイベントしか発動しませんが、別のタイマーを追加して1秒あたり2回のイベントが発生し、このように蓄積し続けます。最終的には、TickハンドラとAnimatedRenderMessageHandlerがCPUを立ち上げて、画面が暴走して画面を更新できなくなるのを見るでしょう。それはまた、なぜあなたの症状がより早く現れるようにタイマーの発火の頻度を上げるのか説明します。

修正は簡単です:Clockオブジェクトの処理が完了したら、DispatcherTimerを停止または破棄するだけです。

+0

私は時計のインスタンスをVisualツリーから削除する前に呼び出すDisposeTimerメソッドを含むようにClockクラスを再構築しました。私は問題が解決するかどうかを今すぐテストしています。私は指を横切っています。 – discorax

+0

Clockクラスを再作成すると、いくつかの問題が修正されたようです。私はこの質問に恩恵を与えたので、私は答えを受けなければなりませんでしたが、DispatcherTimerの問題はまだ顕著です。私は、複数のスレッドを扱っている経験豊富な人がチャイムインしてもらいたいと思っていましたが、そうではありませんでした。 ご協力いただきありがとうございます。 – discorax

+0

DispatcherTimer自体の問題ではなく、DispatcherTimer自体の問題であると考えていますか? Clock_Tickメソッドが呼び出されている頻度を確認しましたか?DispatcherTimerはかなり安定しています。定期的に、UIスレッドが呼び出すメソッドをキューに配置するだけです。あなたのアプリがUI上のCPU使用量が過剰であり、スレッドをレンダリングするためにロックされている場合は、本当はマルチスレッド問題ではありません。なぜなら、なぜUIスレッドへの呼び出しが多いのですか? – RandomEngy

1

をあなたはそれがDispatcherTimerだと仮定して、その上で完全に焦点を当てているのが残念それは5時間かかります。私は個人的には、タイマー自体とは何かを持っていると信じ苦労を持っていますタイマーティックの中で何が起こっているのか正確に教えてもらえますか?

+0

面白い、あなたはそれを言及する必要があります。それはまさに私が始めたところです。実際には私の最初の質問は正確でしたので、私はそれを再び追加します。 – discorax

+0

その詳細を追加していただきありがとうございます。だからあなたはAnglesの値を変更するだけですが、これは非常に問題でもあります。 タイマーを10分の1秒または100分の1秒のように変更できますか?実際にこのタイマーループと関係がある場合は、プロセスを高速化するのに役立ちますので、再現するほうがはるかに簡単です。 –

+0

それは良い提案です。私はそれをし、それは問題を加速するようです。私が参照するコンストラクタは、毎回Clockクラスのインスタンスを作成しているもう1つの詳細です。 ClockオブジェクトがGCによって適切に収集されていない可能性がありますが、それが原因である可能性があります。 – discorax

1
hHandRT.Angle = _hAngle; 
mHandRT.Angle = _mAngle; 
sHandRT.Angle = _sAngle; 

私は上記のコードをもう一度見なければならないと思います。

毎秒変更する必要がない場合でも、3つのトランスフォームすべてに対してトランスフォームのAngleプロパティを設定しています。 60回の変更ごとに分が変更され、3600秒ごとに時間が変更されます。しかし、1秒ごとに変化する時間を少なくともatleast減らすことができます。あなたがWPFへの変更を変換要求する場合、必ずここで何が起こっている

は、ある、WPFは、優先順位ディスパッチキューに要求をキューに入れ、毎秒あなたはそれを処理することができます行うことに多くの変更を推進しています。これが、メモリの代わりにCPU使用率が増加し続ける唯一の理由です。

詳細分析:あなたのコードを見た後、私は

を、あなたのDispatcherTimer_Tickイベントは計算のあまりないと感じた場合ディスパッチャスレッドがすでに、イベントのルーティング、視覚的な更新などを管理するなどの観光名所がたくさん過負荷になって覚えていますディスパッチャスレッドでカスタムタスクを実行するためにCPUをさらにビジー状態に保ちます。毎秒2回目のイベントでも、保留中のタスクのキューを確実に増やし続けます。

あなたはダニの実行時間をプロファイリングし、表示されるはずですあなたはそのに小さな乗​​算計算を考えるかもしれないが、それはロードタイムゾーンに来るときディスパッチャスレッドのためにそれは高価なことができ、時間等の値を変換します。

ティックイベントごとに別のスレッドで実行されるSystem.Threading.Timerオブジェクトを使用して、必要な最終角度の計算が完了したらDispatcherスレッドに渡すことができます。これにより

Dispatcher.BeginInvoke((Action)delegate(){ 
    hHandRT.Angle = _hAngle; 
    mHandRT.Angle = _mAngle; 
    sHandRT.Angle = _sAngle; 
}); 

、などの

、あなたはディスパッチャスレッド少しからの作業負荷を軽減します。

+0

私は、ディスパッチャスレッドのすべての作業を実行しないことでパフォーマンスが向上することに同意しますが、元の投稿の問題に直接対処するようには見えません。これは長期的には良いアイデアかもしれませんが、実際には上記の日付の計算よりも角度を変更する上でのオーバーヘッドが増えていると思われますので、少しオーバーオプティマイゼーションになるかもしれません。 –

+0

ディスパッチャオブジェクトのキュー長をプロファイルして調べることができますが、ディスパッチャオブジェクトのPriorityQueueはプライベートメンバーなので、表示方法はわかりません。しかし、あなたが確かにディスパッチャキューに多くを押し込んでから処理できるので、より長い用語が良いアイデアかもしれません。私はディスパッチャのスレッドで深く勉強しました。時には別のスレッド上の2〜3ミリ秒のコードでさえ少し違いがあります。 –

+0

Dispatcherメソッドで実行されるこの例の作業量は、まったく些細なものです。私は同様のプログラムを嘲笑し、1ミリ秒ごとにイベントを発生させ、プログラムは1%の平均CPU使用率を下回っていました。私はDrewに同意します:tickメソッドのCPU使用に焦点を当てるのは早すぎる最適化です。 – RandomEngy

関連する問題