基本的な問題
ビジー インジケータが停止している理由は、時間SomeMethodWhichDoesWork
がかかりすぎるためです。実行中は、Dispatcher で他の作業が行われないようにします。
アニメーションを処理するために生成された入力およびレンダリングの優先度の操作は、通常よりも低くなりますが、バックグラウンド操作よりも優先度が高くなります。ただし、Dispatcher での操作は、優先度の高い操作のエンキューによって中断されることはありません。そのため、レンダリング操作は、バックグラウンド操作であっても、実行中の操作を待機する必要があります。
DispatcherScheduler での監視に関する注意事項
ObserveOn(DispatcherScheduler)
デフォルトでは、通常の優先度ですべてをプッシュします。Rx の最近のバージョンでは、優先順位を指定できるオーバーロードがオンになっています。
見落とされがちな強調すべきポイントの 1 つは、項目が次々に到着するとすぐに DispatcherScheduler によって Dispatcher のキューに入れられることです。
したがって、3000 個のアイテムがすべてかなり近くにある場合、3000 個の通常の優先度の操作が Dispatcher にバックアップされ、それらが完了するまで同じまたはそれより低い優先度のすべてをブロックします (レンダリング操作を含む)。これはほぼ間違いなくあなたが見たものです - つまり、UI 更新の負荷によっては、バックグラウンド スレッドで UI 更新作業以外のすべてを実行しても、問題が発生する可能性があることを意味します。
これに加えて、Lee が言うように、UI スレッドでサブスクリプション全体を実行していないことを確認する必要があります。私は通常、Subscribe
SubscribeOn を使用するのではなく、バックグラウンド スレッドを使用するようにコードを記述しますが、これもまったく問題ありません。
推奨事項
何をするにしても、できるだけ多くの作業をバックグラウンド スレッドで行います。その点は、StackOverflow や他の場所で完全に実行されています。これをカバーするいくつかの優れたリソースを次に示します。
多数の小さな更新に直面しても UI の応答性を維持したい場合は、次のいずれかを実行できます。
- 優先度の低いアイテムをスケジュールします。これは便利で簡単ですが、特定の優先度が必要な場合はあまり適していません
- 更新を独自のキューに保存してキューに入れ、実行する各操作を実行させます。最後のステップとして、キューから次のアイテムを呼び出します。
全体像
少し立ち止まって全体像を見てみる価値もあります。
3000 個のアイテムを連続して UI に個別にダンプすると、ユーザーはどうなりますか? せいぜい、リフレッシュレートが100Hzのモニターを実行することになりますが、おそらくそれよりも低いでしょう. ほとんどの目的には、毎秒 10 のフレーム レートで十分すぎることがわかりました。
それだけでなく、人間は一度に 5 ~ 9 ビット以上の情報を処理することはできないと考えられています。そのため、情報を集約して表示するには、非常に多くの情報を一度に更新するよりも優れた方法が見つかるかもしれません。たとえば、一度にすべてを画面に表示するのではなく、マスター/詳細ビューを利用します。
もう 1 つのオプションは、UI の更新が引き起こしている作業量を確認することです。一部のコントロール (私は XamDataGrid を見ています) は、非常に長い測定/配置レイアウト操作を持つことができます。アニメーションを単純化できますか? より単純なビジュアル ツリーを使用しますか? 丸い点のように見える人気のビジー スピナーについて考えてみてください。実際には、色が変わっているだけです。かなり安価に達成できる素晴らしい効果。アプリケーションのプロファイリングを行って、時間の経過を確認する価値があります。
前後の全体的なアプローチについても考えます。一度に多くのアイテムを更新することが合理的に確実な場合は、それらをバッファリングしてチャンクで管理してみませんか? それはソースにまでさかのぼる利点があるかもしれません-おそらくどこかのサーバー上にありますか? いずれにせよ、Rx には、個々の項目のストリームをより大きなリストに変換できるような優れた演算子がいくつかあります。またBuffer
、時間とサイズで一緒にバッファリングできるオーバーロードがあります。