在我的應用程序中,我注意到我處理事件的方式導致性能問題。性能問題 - 取消訂閱事件
我想知道如果這是預期的,也許我在那裏做錯了什麼。 有沒有辦法解決我的問題?
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var x = new Main();
x.Init();
Console.ReadLine();
}
}
public class Main
{
private Bar _bar;
private List<Foo> _foos;
public Main()
{
_bar = new Bar();
}
public void Init()
{
var sw = new Stopwatch();
sw.Restart();
_foos = new List<Foo>();
for (int i = 0; i < 10000; i++)
{
var newFoo = new Foo();
newFoo.Bar = _bar;
_foos.Add(newFoo);
}
sw.Stop();
Console.WriteLine("Init 10.000 Foos WITH un-subscribe event: {0} ms", sw.ElapsedMilliseconds);
_foos.Clear();
sw.Restart();
_foos = new List<Foo>();
for (int i = 0; i < 10000; i++)
{
var newFoo = new Foo();
newFoo.BarWithout = _bar;
_foos.Add(newFoo);
}
sw.Stop();
Console.WriteLine("Init 10.000 Foos WITHOUT un-subscribe event: {0} ms", sw.ElapsedMilliseconds);
_foos.Clear();
}
}
public class Bar
{
public event EventHandler<string> Stuff;
protected virtual void OnStuff(string e)
{
var stuff = this.Stuff;
if (stuff != null)
stuff(this, e);
}
}
public class Foo
{
private Bar _bar;
public Bar Bar
{
get { return _bar; }
set
{
if (_bar != null)
{
_bar.Stuff -= _bar_Stuff;
}
_bar = value;
if (_bar != null)
{
_bar.Stuff -= _bar_Stuff;
_bar.Stuff += _bar_Stuff;
}
}
}
public Bar BarWithout
{
get { return _bar; }
set
{
if (_bar != null)
{
//_bar.Stuff -= _bar_Stuff;
}
_bar = value;
if (_bar != null)
{
//_bar.Stuff -= _bar_Stuff;
_bar.Stuff += _bar_Stuff;
}
}
}
private void _bar_Stuff(object sender, string e)
{
}
}
}
在此示例代碼,我Foo
類有2個屬性Bar
和BarWithout
。 BarWithout
屬性已取消訂閱評論。
在Main
類的Init
方法我建立2倍10.000Foo
對象和所述第一例程設置Bar
性的第二設置BarWithout
屬性。在我的機器上,第一個程序需要約2200毫秒,第二個程序需要約5ms。
由於差距有點巨大,我想知道是否有更有效的方法來刪除事件處理程序?
順便說一句,我知道我可以改變代碼,以便Main訂閱Bar的事件,並且爲列表中的所有Foo對象調用一個方法,但是希望有一些「更容易」,而不需要重構現在的情況。
編輯:
具有4倍的數據(如此40.000代替10.000)的第一例程已花費〜28.000毫秒相比〜20毫秒,所以第一個例程是隻用慢10倍以上4倍以上的數據。第二個例程保持不變,性能提高4倍,數據速度減慢4倍。
'_bar.Stuff - = _bar_Stuff;'的問題,它是在一個MulticastDelegate爲O(n)的操作。在這個測試中,它必須通過大量代表來尋找可能的匹配。在同一個_bar變量的循環中做到這一點使得它O(n^2),二次算法開始非常快地吸吮。很難給出具體的建議,代碼是非常人爲的,通常_bar將是一個不同的對象。 –