Отменить подписку на события - производительность удалась?
Рассмотрим следующий код (из отчета об эффективности):
![Performance report]()
Это часть компонента прослушивателя свойств. Метод OnItemPropertyChanged
представляет собой частный метод привязки к экземпляру с сигнатурой PropertyChangedEventHandler
. Этот метод называется примерно 100 000 раз и вызывает значительные задержки в приложении.
Есть ли соображения производительности, связанные с (un) подписными событиями? Есть ли объяснение, почему это может привести к такому результату?
Ответы
Ответ 1
Что касается недостатка дизайна, о котором говорят многие комментарии, мы сильно убеждены в том, что пользователи не будут помещать объектный граф с 100k объектами в целом в пользовательский интерфейс; это часть непрерывного процесса совершенствования и, надеюсь, будет решена в будущем.
Не было существенной разницы между ссылкой sharedHandler
и Method
, передаваемой оператору отмены подписки.
Использование слабый менеджер событий устраняет поражение производительности; с или без создания таких делегатов, как Марк Гравелл. Возможно, это связано с тем, что этот класс создает свой собственный прослушиватель событий другим способом, а не использует тот, который указан в его аргументе. Я просмотрел source, но не смог найти объяснения, почему этот шаблон работает быстро (поскольку +=
и -=
все еще вызываются).
Ответ 2
Обратите внимание, что 94.2%
связано с относительным временем выполнения. Таким образом, отмена подписки занимает 94.2%
от общего времени выполнения метода Disable(..)
. И учитывая, что другие необработанные коды кода cast
и null
проверяют, это нормально.
Реальная проблема, imo (даже если что-либо в отношении производительности строго зависит от конкретного контекста выполнения) заключается в том, что этот метод называется 100.000
times.
Ответ 3
Прежде всего следует отметить, что:
notificationItem.PropertyChanged -= OnItemPropertyChanged;
на самом деле выделенный новый делегат для этой цели. Это также означает, что тест эквивалентности не может быть короткозамкнутым при эквивалентности идентичности - он должен выполнять эквивалентность метода/цели (т.е. Другой экземпляр делегата, но тот же целевой/метод, поэтому считается эквивалентным для целей делегирования).
Сначала я попытался бы использовать один экземпляр делегата, т.е.
void OnItemPropertyChanged(object sender, PropertyChangedEventArgs args) {...}
private readonly PropertyChangedEventHandler sharedHandler;
public YourType() { // constructor
sharedHandler = OnItemPropertyChanged;
}
Затем, когда вы подписываетесь, вместо:
notificationItem.PropertyChanged += OnItemPropertyChanged;
или
notificationItem.PropertyChanged -= OnItemPropertyChanged;
используйте вместо этого:
notificationItem.PropertyChanged += sharedHandler;
или
notificationItem.PropertyChanged -= sharedHandler;
Стоит попробовать, по крайней мере.