A magam nevében csak a méréseimet és eredményeimet szeretném bemutatni, ezekhez fordított hurkokat adtam a „C++ stílus” íráshurkok kedvelőinek.
Kód:
public class Bench
{
private List<int> _list;
private int[] _array;
[Params(100000, 10000000)] public int N;
[GlobalSetup]
public void Setup()
{
const int MIN = 1;
const int MAX = 10;
Random random = new Random();
_list = Enumerable.Repeat(0, N).Select(i => random.Next(MIN, MAX)).ToList();
_array = _list.ToArray();
}
[Benchmark]
public int ForList()
{
int total = 0;
for (int i = 0; i < _list.Count; i++)
{
total += _list[i];
}
return total;
}
[Benchmark]
public int ForListFromEnd()
{
int total = 0;t
for (int i = _list.Count-1; i > 0; i--)
{
total += _list[i];
}
return total;
}
[Benchmark]
public int ForeachList()
{
int total = 0;
foreach (int i in _list)
{
total += i;
}
return total;
}
[Benchmark]
public int ForeachArray()
{
int total = 0;
foreach (int i in _array)
{
total += i;
}
return total;
}
[Benchmark]
public int ForArray()
{
int total = 0;
for (int i = 0; i < _array.Length; i++)
{
total += _array[i];
}
return total;
}
[Benchmark]
public int ForArrayFromEnd()
{
int total = 0;
for (int i = _array.Length-1; i > 0; i--)
{
total += _array[i];
}
return total;
}
}
A .NET Core 2.2 és 3.0 teljesítménye szinte azonos. A következőket sikerült megszereznem a .NET Core 3.0-ban:
Arra a következtetésre juthatunk, hogy egy tömbgyűjtemény iteratív feldolgozása gyorsabb a belső optimalizálás és az explicit gyűjteményméret-allokáció miatt. Azt is érdemes megjegyezni, hogy a List gyűjteménynek megvannak a maga előnyei, és a megfelelő gyűjteményt kell használnia a szükséges számításoktól függően. Még ha logikát ír is a hurkokkal való munkavégzéshez, ne felejtse el, hogy ez egy közönséges hurok, és az esetleges hurokoptimalizálásnak is alá esik. Elég régen megjelent egy cikk a habron: https://habr.com/ru/post/124910/. Továbbra is aktuális és ajánlott olvasmány.
Dobás
Egy évvel ezelőtt dolgoztam egy cégnél egy örökölt projekten, abban a projektben normális volt, hogy a terepellenőrzést egy try-catch-throw konstrukcióval dolgozták fel. Már akkor megértettem, hogy ez egészségtelen üzleti logika a projekthez, ezért lehetőség szerint igyekeztem nem ilyen kialakítást alkalmazni. De nézzük meg, miért rossz a hibakezelés megközelítése egy ilyen konstrukcióval. Írtam egy kis kódot a két megközelítés összehasonlítására, és referenciaértékeket készítettem az egyes lehetőségekhez.
Kód:
public bool ContainsHash()
{
bool result = false;
foreach (var file in _files)
{
var extension = Path.GetExtension(file);
if (_hash.Contains(extension))
result = true;
}
return result;
}
public bool ContainsHashTryCatch()
{
bool result = false;
try
{
foreach (var file in _files)
{
var extension = Path.GetExtension(file);
if (_hash.Contains(extension))
result = true;
}
if(!result)
throw new Exception("false");
}
catch (Exception e)
{
result = false;
}
return result;
}
A .NET Core 3.0 és Core 2.2 eredményei hasonlóak (.NET Core 3.0):
A try catch nehezebbé teszi a kód megértését, és megnöveli a program végrehajtási idejét. De ha szüksége van erre a konstrukcióra, ne illessze be azokat a kódsorokat, amelyek várhatóan nem kezelik a hibákat - ez megkönnyíti a kód megértését. Valójában nem is annyira a kivételek kezelése tölti be a rendszert, hanem inkább maguk a hibák dobása a throw new Exception konstrukción keresztül.
A kivételek dobása lassabb, mint néhány olyan osztály, amely a hibát a kívánt formátumban gyűjti össze. Ha egy űrlapot vagy néhány adatot dolgoz fel, és egyértelműen tudja, mi lehet a hiba, miért ne dolgozná fel?
Ne írj új Exception() konstrukciót, ha ez a helyzet nem kivételes. A kivétel kezelése és dobása nagyon drága!!!
A .NET platformon végzett 5 éves tapasztalatom során számos olyan projekttel találkoztam, amelyek karakterlánc-illesztést használtak. A következő képet is láttam: volt egy Enterprise-megoldás, sok projekttel, amelyek mindegyike eltérően hajtotta végre a karakterlánc-összehasonlításokat. De mit érdemes használni és hogyan lehet egységesíteni? A Richter CLR via C# című könyvében azt olvastam, hogy a ToUpperInvariant() metódus gyorsabb, mint a ToLowerInvariant().
Részlet a könyvből:
Természetesen nem hittem el, és úgy döntöttem, hogy futtatok néhány tesztet a .NET-keretrendszeren, és az eredmény sokkolt – több mint 15%-os teljesítménynövekedés. Másnap reggel munkába érve megmutattam ezeket a méréseket a feletteseimnek, és hozzáférést adtam a forráskódhoz. Ezt követően 2 projektből 14-ben módosult az új méréseknek megfelelően, és tekintve, hogy ez a két projekt hatalmas Excel táblák feldolgozására létezett, az eredmény több mint jelentős volt a termék szempontjából.
Méréseket is bemutatok a .NET Core különböző verzióihoz, hogy mindenki döntse el a legoptimálisabb megoldást. És csak azt szeretném hozzátenni, hogy abban a cégben, ahol dolgozom, a ToUpper()-t használjuk a karakterláncok összehasonlítására.
Kód:
public const string defaultString = "VXTDuob5YhummuDq1PPXOHE4PbrRjYfBjcHdFs8UcKSAHOCGievbUItWhU3ovCmRALgdZUG1CB0sQ4iMj8Z1ZfkML2owvfkOKxBCoFUAN4VLd4I8ietmlsS5PtdQEn6zEgy1uCVZXiXuubd0xM5ONVZBqDu6nOVq1GQloEjeRN8jXrj0MVUexB9aIECs7caKGddpuut3";
[Benchmark]
public bool ToLower()
{
return defaultString.ToLower() == defaultString.ToLower();
}
[Benchmark]
public bool ToLowerInvariant()
{
return defaultString.ToLowerInvariant() == defaultString.ToLowerInvariant();
}
[Benchmark]
public bool ToUpper()
{
return defaultString.ToUpper() == defaultString.ToUpper();
}
[Benchmark]
public bool ToUpperInvariant()
{
return defaultString.ToUpperInvariant() == defaultString.ToUpperInvariant();
}
A .NET Core 3.0-ban ezeknek a metódusoknak a növekedése ~x2, és egyensúlyba hozza a megvalósításokat egymás között.
Tier összeállítás
Legutóbbi cikkemben röviden ismertettem ezt a funkciót, szeretném javítani és kiegészíteni szavaimat. A többszintű fordítás felgyorsítja a megoldás indítási idejét, de fel kell áldoznia, hogy a kód egyes részei a háttérben optimalizáltabb verzióba kerüljenek, ami kis többletköltséget jelenthet. A NET Core 3.0 megjelenésével lecsökkent a rétegösszeállítást engedélyező projektek felépítési ideje, és kijavították az ezzel a technológiával kapcsolatos hibákat. Korábban ez a technológia hibákhoz vezetett az ASP.NET Core első kéréseiben, és lefagyott az első összeállítás során többszintű fordítási módban. Jelenleg alapértelmezés szerint engedélyezve van a .NET Core 3.0-ban, de tetszés szerint letilthatja. Ha Ön csapatvezető, vezető, középső pozícióban van, vagy egy osztály vezetője, akkor meg kell értenie, hogy a gyors projektfejlesztés növeli a csapat értékét, és ez a technológia lehetővé teszi, hogy időt takarítson meg mindkét fejlesztő számára. és magának a projektnek az ideje.
.NET szinttel feljebb
Frissítse a .NET Framework / .NET Core verzióját. Gyakran minden új verzió további teljesítménynövekedést és új funkciókat ad hozzá.
De pontosan mik az előnyei? Nézzünk ezek közül néhányat:
A .NET Core 3.0 bevezette az R2R lemezképeket, amelyek csökkentik a .NET Core alkalmazások indítási idejét.
A 2.2-es verzióval megjelent a Tier Compilation, aminek köszönhetően a programozók kevesebb időt töltenek a projekt elindításával.
Új .NET szabványok támogatása.
A programozási nyelv új verziójának támogatása.
Optimalizálás, minden új verzióval javul a Gyűjtemény/Struktúra/Stream/String/Regex és még sok más alapkönyvtár optimalizálása. Ha a .NET-keretrendszerről a .NET Core-ra költözik, nagy teljesítménynövekedést kaphat. Példaként csatolok egy hivatkozást a .NET Core 3.0-hoz hozzáadott néhány optimalizáláshoz: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/
Következtetés
A kód írásakor érdemes odafigyelni a projekt különböző aspektusaira, és a legjobb eredmény elérése érdekében felhasználni a programozási nyelv és a platform szolgáltatásait. Örülnék, ha megosztaná tudását a .NET-ben történő optimalizálással kapcsolatban.