У меня проблема, когда приложение работает очень медленно, потому что есть события с тысячами прикрепленных к нему обработчиков, и удаление этих обработчиков происходит очень медленно. Мое приложение работает как процесс .NET Framework 4.8,
Я написал тестовую программу (но с .NET 5), в которой я заменил событие собственной реализацией, в которой я использовал HashSet для хранения обработчиков и сам реализовал добавление / удаление обработчиков события.
Мое тестовое приложение работало отлично, но после применения этого решения к моему реальному приложению производительность все еще была плохой.
Затем я понял, что причина, по-видимому, заключается в разнице во времени выполнения. Следующий пример программы работает быстро (примерно 1 секунда в .NET 5, но работает несколько минут при запуске того же кода в приложении .NET Framework 4.8):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
namespace EventPerformaneMeasurement
{
class Program
{
private static void Main()
{
var sw = new Stopwatch();
var mc = new MyClass();
var list = Enumerable.Range(1, 1_000_000).Select(x => new PropertyChangedEventHandler((_, _) => { Console.WriteLine($"Handler {x} called"); })).ToList();
sw.Restart();
list.ForEach(handler=>mc.PropertyChangedNew += handler);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();
list.ForEach(handler=>mc.PropertyChangedNew -= handler);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
class MyClass
{
private HashSet<PropertyChangedEventHandler> _handlers = new();
public event PropertyChangedEventHandler PropertyChangedNew
{
add => _handlers.Add(value);
remove => _handlers.Remove(value);
}
}
}
Я создал две скрипки .NET для воспроизведения этого поведения, скрипка .NET потребовала от меня немного изменить синтаксис моего примера кода и уменьшить количество итераций со 1000000 до 15000, но разница в производительности все еще видна:
Я не могу поверить, что существует такая большая разница между .NET 5 и .NET Framework 4.x в отношении производительности HashSet.
Кто-нибудь знает больше об этом эффекте или где я, может быть, застрял? Есть ли способ получить такую же производительность в .NET 4.8 другим способом?