Model jest typem używanym w kompilatorze Roslyn C# do wielokrotnego użytku często używanych obiektów, które zwykle bardzo często pobierają nowe wiadomości i zbierają śmieci. Zmniejsza to ilość i rozmiar operacji zbierania śmieci, które muszą się wydarzyć.Dlaczego jest tak wiele implementacji Object Pooling w Roslyn?
Kompilator Roslyn wydaje się mieć kilka oddzielnych pul obiektów, a każda pula ma inny rozmiar. Chcę wiedzieć, dlaczego jest tak wiele implementacji, jaka jest preferowana implementacja i dlaczego wybrano pulę o wielkości 20, 100 lub 128.
1 - SharedPools - Przechowuje pulę 20 obiektów lub 100, jeśli BigDefault jest używany. Ta jest również dziwna, ponieważ tworzy nową instancję PooledObject, co nie ma sensu, gdy próbujemy połączyć obiekty, a nie tworzyć i niszczyć nowe.
// Example 1 - In a using statement, so the object gets freed at the end.
using (PooledObject<Foo> pooledObject = SharedPools.Default<List<Foo>>().GetPooledObject())
{
// Do something with pooledObject.Object
}
// Example 2 - No using statement so you need to be sure no exceptions are not thrown.
List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear();
// Do something with list
SharedPools.Default<List<Foo>>().Free(list);
// Example 3 - I have also seen this variation of the above pattern, which ends up the same as Example 1, except Example 1 seems to create a new instance of the IDisposable [PooledObject<T>][3] object. This is probably the preferred option if you want fewer GC's.
List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear();
try
{
// Do something with list
}
finally
{
SharedPools.Default<List<Foo>>().Free(list);
}
2 - ListPool i StringBuilderPool - Nie ściśle odrębne implementacje ale obwolut wokół realizacji SharedPools przedstawione powyżej specjalnie dla listy i StringBuilder jest. W ten sposób ponownie wykorzystuje pulę obiektów przechowywanych w SharedPools.
// Example 1 - No using statement so you need to be sure no exceptions are thrown.
StringBuilder stringBuilder= StringBuilderPool.Allocate();
// Do something with stringBuilder
StringBuilderPool.Free(stringBuilder);
// Example 2 - Safer version of Example 1.
StringBuilder stringBuilder= StringBuilderPool.Allocate();
try
{
// Do something with stringBuilder
}
finally
{
StringBuilderPool.Free(stringBuilder);
}
3 - PooledDictionary i PooledHashSet - Są używać ObjectPool bezpośrednio i mają całkowicie odrębną pulę obiektów. Przechowuje pulę 128 obiektów.
// Example 1
PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance()
// Do something with hashSet.
hashSet.Free();
// Example 2 - Safer version of Example 1.
PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance()
try
{
// Do something with hashSet.
}
finally
{
hashSet.Free();
}
Aktualizacja
Są nowe implementacje obiekt grupowania w .NET Core. Zobacz moją odpowiedź na pytanie C# Object Pooling Pattern implementation.
Biorąc pod uwagę, że Microsoft zawsze opierał się koncepcji pul obiektów w .NET, ponieważ zawsze twierdził, że GC obiektów gen0 jest bardzo szybki, jest to interesujący zwrot :-) – xanatos
Po przeczytaniu, myślę, że kompilator Roslyn jest specjalnym razem z StackOverflow, co jest kolejnym przykładem, jaki znam, który to robi. Obiekt gromadzący chroni przed zbiorami gen2, które mogą powodować przerwy w aplikacji drugiego lub więcej, chociaż nie jestem pewien dokładnego czasu. Wadą tego podejścia jest to, że zużywasz więcej pamięci, ponieważ nigdy nie usuwasz połączonych obiektów. –
Kompilator nie jest aplikacją czasu rzeczywistego, w której nie chcesz pauzować ... I nie jest to tak, że setka użytkowników łączy się jednocześnie. Chcieli go zoptymalizować, ponieważ nie chcieli, aby był wolniejszy od starszego kompilatora i korzystali z Object Pool ... Ale to nie znaczy, że muszę polubić to, co zrobili. – xanatos