ブロックコレクションからアイテムのグループを試すことができますか?
質問
私が取り組んでいるアプリケーションでは、毎秒何千もの更新が受けられています。これらのアップデートをすぐにUIで反映させ、1つずつパフォーマンスのオーバーキル。
次のコードは非常に悪いパフォーマンスを得ます。
foreach (var update in updates.GetConsumingEnumerable())
{
// Handle Update
}
.
私がしようとしていることは、消費者に少し待って(すなわち50ミリ秒)、出版社にもっと商品を追加し、次にこれらの更新をチャンクで処理します。
現在、私は次のコードを使用していますが、消費される前にアイテムがコレクションに滞在する期間を予測するのは難しいと思います。
List<Tuple<T, List<string>>> updatesToHandle = new List<Tuple<T, List<string>>>();
while (!updates.IsAddingCompleted)
{
Tuple<T, List<string>> item = null;
if (updates.TryTake(out item, 5)) // Try Take for 5 Milliseconds
{
updatesToHandle.Add(item);
}
else
{
var newItems = new List<T>(updatesToHandle.Count);
var updatedItems = new List<Tuple<T, List<string>>>(updatesToHandle.Count);
foreach (var update in updatesToHandle)
{
try
{
// Handle Update
}
finally
{
updatesToHandle.Clear();
Thread.Sleep(50);
}
}
}
}
. 解決
Reactive Extensions > ReactiveExtensions 。このリンクは、同様の問題を解決します株式取引の例
他のヒント
あなたのコードに2つの変更を提案します。
最初に、スレッドスリープを持つのではなく、50ミリ秒ごとに発生するタイマーを作成します。その場合、そのタイマーハンドラは遅延なしでTryTake
をループし、現在コレクション内にあるすべての項目を収集します(または最大値まで)。遅延なしで、Collectionが空の場合、TryTake
はすぐに戻ります。
秒で、更新ごとに1回「更新UI」を呼び出さないでください。一度に1回の更新ではなくアップデートのリスト全体を受け入れるように更新ハンドラを変更します。それはUIスレッドを待つのにかかる時間を避けます。
上記は、もちろん、アップデートハンドラを1つのショットでObservableCollection
に複数の項目を追加できるように変更したことを前提としています。
第2のRx。具体的には、BufferByTime(着信率が高いときに集約する場合)またはスロットル(着信率が高すぎる場合は値を離している場合)が必要です。また、あなたのUIはおそらくBehaviorSubjectにバインドされるべきです。