3

私が取り組んでいるアプリケーションでは、毎秒数千の更新が受信されています。これらの更新をすぐに UI に反映するのは、パフォーマンスが過剰です。

次のコードでは、各更新を処理するために UI スレッドを呼び出し、ObservableCollection に新しいアイテムを追加する必要があるため、パフォーマンスが非常に悪くなります。これにより、CollectionChanged イベントがトリガーされます。

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);
            }
        }
    }
}
4

3 に答える 3

3

Reactive Extensions ReactiveExtensionsの使用を検討します。このリンクは同様の問題を解決します株式取引の例

于 2012-10-01T05:41:02.883 に答える
1

コードに2つの変更を加えることをお勧めします。

まず、スレッドをスリープ状態にするのではなく、50ミリ秒ごとに起動するタイマーを作成します。その後、そのタイマーハンドラーはTryTake遅延なしでループし、現在コレクションにあるすべてのアイテム(または最大値まで)を収集します。遅れることなくTryTake、コレクションが空の場合はすぐに戻ります。

次に、更新ごとに1回「更新UI」を呼び出さないでください。一度に1つの更新ではなく、更新のリスト全体を受け入れるように更新ハンドラーを変更します。これにより、UIスレッドの待機にかかる時間を回避できます。

もちろん、上記は、更新ハンドラーを変更して、複数のアイテムをObservableCollection1回のショットで追加し、複数のCollectionChangedイベントを防止できることを前提としています。

于 2012-09-30T22:25:32.770 に答える
0

私は2番目のRxです。具体的には、BufferByTime (着信レートが高いときに集計する場合) または Throttle (着信レートが高すぎるときに値を破棄する場合) が必要です。また、UI はおそらく BehaviorSubject にバインドする必要があります。これは常に最後の値をキャッシュするため、新しいサブスクライバーはサブスクライブ時に最後にキャッシュされた値をすぐに取得します。

于 2013-01-11T19:54:52.817 に答える