Closed kenichi-kobayashi closed 3 years ago
処理時間、メモリ共に、大幅の改善が行われたことを確認できました。 V7.8.0のリリースありがとうございます。
そして、更なる課題が出てきたので、相談させてください。
前回の実験では、Itemsに100万オブジェクトを生成した後に、ToFilteredを実行してIFlteredROOCを作成していました。
public MyItemsViewModel() { Items = new ObservableCollection<MyItemViewModel>(); Enumerable.Range(1, 1000000).Select(a => new MyItemViewModel(a)).ToList().ForEach(a => Items.Add(a)); FilteredItems = Items.ToFilteredReadOnlyObservableCollection(item => item.Value % 2 == 0); Count = FilteredItems.CountAsObservable().ToReadOnlyReactivePropertySlim(); }
Rpを7.8.0にすることで、このコードの処理時間が5秒程度になり実用可能レベルの処理時間になりました。 ただ、IFlteredROOCを実用する多くは場合、Itemsの生成と同時に生成するシーンが多いかと思います。
public MyItemsViewModel2() { Items = new ObservableCollection<MyItemViewModel>(); FilteredItems = Items.ToFilteredReadOnlyObservableCollection(item => item.Value % 2 == 0).AddTo(disposables); Count = FilteredItems.CountAsObservable().ToReadOnlyReactivePropertySlim(); Enumerable.Range(1, 1000000).Select(a => new MyItemViewModel(a)).ToList().ForEach(a => Items.Add(a)); }
これを実行すると、1時間以上の時間がかかってしまい、実用が難しいことが分かってきました。 これを回避するために、以下のとおりに対策したらどうか?と思っています。
■対策:アプリケーション側 ObservableCollectionを継承し、AddRange機能を装備した「RangedObservableCollection」を定義します。 AddRange実行中は、CollectionChangedイベントが発行されないように抑制しておき、登録終了後に、Resetイベントを発行するようにします。 参考URL:https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/
■対策:ReactiveProperty側 ReactiveProperty側では、以下のとおりにResetの処理に細工を入れます。
public FilteredReadOnlyObservableCollection(TCollection source, Func<TElement, bool> filter) の source.CollectionChangedAsObservable() を以下のとおりに修正します。
case NotifyCollectionChangedAction.Reset: Initialize(); // これを追加して //IndexList.Clear(); // これらを外す。 //InnerCollection.Clear(); // これらを外す。 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); //if (source.Any()) // これらを外す。 //{ // これらを外す。 // throw new NotSupportedException("Reset is clear only"); // これらを外す。 //} // これらを外す。 break;
上記対策を実施したところ、以下のコードが5秒程度に収まり実用レベルになりました。
public MyItemsViewModel3() { Items = new RangedObservableCollection<MyItemViewModel>(); FilteredItems = Items.ToFilteredReadOnlyObservableCollection(item => item.Value % 2 == 0).AddTo(disposables); Count = FilteredItems.CountAsObservable().ToReadOnlyReactivePropertySlim(); var items = Enumerable.Range(1, 1000000).Select(a => new MyItemViewModel(a)).ToList(); Items.AddRange(items); }
FilteredReadOnlyObservableCollection.zip
FilteredAddRangeTest.zip
対応を入れたものを 7.8.1 のプレリリース版としてリリースのパイプラインを走らせてみました。 確認お願いします。
処理時間、メモリ共に、大幅の改善が行われたことを確認できました。 V7.8.0のリリースありがとうございます。
そして、更なる課題が出てきたので、相談させてください。
前回の実験では、Itemsに100万オブジェクトを生成した後に、ToFilteredを実行してIFlteredROOCを作成していました。
Rpを7.8.0にすることで、このコードの処理時間が5秒程度になり実用可能レベルの処理時間になりました。 ただ、IFlteredROOCを実用する多くは場合、Itemsの生成と同時に生成するシーンが多いかと思います。
これを実行すると、1時間以上の時間がかかってしまい、実用が難しいことが分かってきました。 これを回避するために、以下のとおりに対策したらどうか?と思っています。
■対策:アプリケーション側 ObservableCollectionを継承し、AddRange機能を装備した「RangedObservableCollection」を定義します。 AddRange実行中は、CollectionChangedイベントが発行されないように抑制しておき、登録終了後に、Resetイベントを発行するようにします。 参考URL:https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/
■対策:ReactiveProperty側 ReactiveProperty側では、以下のとおりにResetの処理に細工を入れます。
public FilteredReadOnlyObservableCollection(TCollection source, Func<TElement, bool> filter) の source.CollectionChangedAsObservable() を以下のとおりに修正します。
上記対策を実施したところ、以下のコードが5秒程度に収まり実用レベルになりました。
FilteredReadOnlyObservableCollection.zip
FilteredAddRangeTest.zip