Сообщение Re[14]: Observable computations от 20.11.2019 10:56
Изменено 20.11.2019 12:09 igor-booch
Re[14]: Observable computations
S>2. Можно ли обойтись без порождения N врапперов для N элементов исходной коллекции — это ж реально адский перерасход по памяти. ObservableCollection<int> из миллиона элементов потребляет памяти почти столько же, сколько голый int[1000000]. А приделывание к ней банального "filtering" у нас что — порождает миллион экземпляров Computing() в куче?
Миллион экземпляров Computing() будет порождаться если только если
1) Computing() вложен в предикат
2) Computing() должен зависеть от параметра предиката.
Я бы не сказал, что это банальный filtering.
Вычисление можно сделать плоским (то есть убрать вложенные параметрозависимые вычисления). Наше вычисление можно переписать так:
Выглядит менее очевидно, но зато с памятью будет значительно лучше. И без вложенных Computing'ов.
S>3. Что делать с зависимыми коллекциями, которые больше не нужны?
S>Ведь сейчас они подписываются на события оригинала, и, таким образом, "привязываются" к нему. Если я буду в цикле создавать new Filtering() от ObservableCollection, то GC их никогда не соберёт, из-за наличия ссылок на обработчики в событиях observableCollection.
Эта проблема не стоит. Используются слабые события.
Миллион экземпляров Computing() будет порождаться если только если
1) Computing() вложен в предикат
2) Computing() должен зависеть от параметра предиката.
Я бы не сказал, что это банальный filtering.
Вычисление можно сделать плоским (то есть убрать вложенные параметрозависимые вычисления). Наше вычисление можно переписать так:
ObservableCollection<Order> filteredOrders = orders
.Joining(selectedOrderTypes, (o, ot) => o.Type == ot)
.Selecting(oot => oot.OuterItem);
Выглядит менее очевидно, но зато с памятью будет значительно лучше. И без вложенных Computing'ов.
S>3. Что делать с зависимыми коллекциями, которые больше не нужны?
S>Ведь сейчас они подписываются на события оригинала, и, таким образом, "привязываются" к нему. Если я буду в цикле создавать new Filtering() от ObservableCollection, то GC их никогда не соберёт, из-за наличия ссылок на обработчики в событиях observableCollection.
Эта проблема не стоит. Используются слабые события.
[Test, Combinatorial]
public void Selecting_Dispose(
[Range(0, 4, 1)] int index,
[Range(-1, 5)] int newValue)
{
ObservableCollection<Item> items = new ObservableCollection<Item>(
new[]
{
new Item(),
new Item(),
new Item(),
new Item(),
new Item()
}
);
WeakReference<Selecting<Item, int>> selectingWeakReference = null;
Action action = () =>
{
Selecting<Item, int> selecting = items.Selecting(item => item.Num);
selectingWeakReference = new WeakReference<Selecting<Item, int>>(selecting);
};
action();
GC.Collect();
Assert.IsFalse(selectingWeakReference.TryGetTarget(out Selecting<Item, int> s));
}
Re[14]: Observable computations
S>2. Можно ли обойтись без порождения N врапперов для N элементов исходной коллекции — это ж реально адский перерасход по памяти. ObservableCollection<int> из миллиона элементов потребляет памяти почти столько же, сколько голый int[1000000]. А приделывание к ней банального "filtering" у нас что — порождает миллион экземпляров Computing() в куче?
Миллион экземпляров Computing() будет порождаться если только если
1) Computing() вложен в предикат
2) Computing() должен зависеть от параметра предиката.
Я бы не сказал, что это банальный filtering.
Вычисление можно сделать "плоским" (то есть убрать вложенные параметрозависимые вычисления). Наше вычисление можно переписать так:
Выглядит менее очевидно, но зато с памятью будет значительно лучше. И без вложенных Computing'ов.
S>3. Что делать с зависимыми коллекциями, которые больше не нужны?
S>Ведь сейчас они подписываются на события оригинала, и, таким образом, "привязываются" к нему. Если я буду в цикле создавать new Filtering() от ObservableCollection, то GC их никогда не соберёт, из-за наличия ссылок на обработчики в событиях observableCollection.
Эта проблема не стоит. Используются слабые события.
Миллион экземпляров Computing() будет порождаться если только если
1) Computing() вложен в предикат
2) Computing() должен зависеть от параметра предиката.
Я бы не сказал, что это банальный filtering.
Вычисление можно сделать "плоским" (то есть убрать вложенные параметрозависимые вычисления). Наше вычисление можно переписать так:
ObservableCollection<Order> filteredOrders = orders
.Joining(selectedOrderTypes, (o, ot) => o.Type == ot)
.Selecting(oot => oot.OuterItem);
Выглядит менее очевидно, но зато с памятью будет значительно лучше. И без вложенных Computing'ов.
S>3. Что делать с зависимыми коллекциями, которые больше не нужны?
S>Ведь сейчас они подписываются на события оригинала, и, таким образом, "привязываются" к нему. Если я буду в цикле создавать new Filtering() от ObservableCollection, то GC их никогда не соберёт, из-за наличия ссылок на обработчики в событиях observableCollection.
Эта проблема не стоит. Используются слабые события.
[Test, Combinatorial]
public void Selecting_Dispose(
[Range(0, 4, 1)] int index,
[Range(-1, 5)] int newValue)
{
ObservableCollection<Item> items = new ObservableCollection<Item>(
new[]
{
new Item(),
new Item(),
new Item(),
new Item(),
new Item()
}
);
WeakReference<Selecting<Item, int>> selectingWeakReference = null;
Action action = () =>
{
Selecting<Item, int> selecting = items.Selecting(item => item.Num);
selectingWeakReference = new WeakReference<Selecting<Item, int>>(selecting);
};
action();
GC.Collect();
Assert.IsFalse(selectingWeakReference.TryGetTarget(out Selecting<Item, int> s));
}