Vo svojom mene vám chcem len predstaviť moje merania a výsledky, pridal som k nim spätné slučky pre milovníkov „C++ štýlu“ písania slučiek.
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;
}
}
Rýchlosti výkonu v .NET Core 2.2 a 3.0 sú takmer totožné. Tu je to, čo sa mi podarilo získať v .NET Core 3.0:
Môžeme konštatovať, že iteratívne spracovanie kolekcie Array je rýchlejšie vďaka jej interným optimalizáciám a explicitnému prideleniu veľkosti kolekcie. Je tiež potrebné pripomenúť, že kolekcia zoznamu má svoje výhody a mali by ste použiť správnu kolekciu v závislosti od požadovaných výpočtov. Aj keď píšete logiku pre prácu so slučkami, nezabudnite, že ide o obyčajnú slučku a podlieha aj prípadnej optimalizácii slučky. Na habr bol už dávno publikovaný článok: https://habr.com/ru/post/124910/. Je to stále relevantné a odporúčané čítanie.
Hádzať
Pred rokom som pracoval v jednej spoločnosti na starom projekte, v tomto projekte bolo normálne spracovať validáciu v teréne pomocou konštruktu vyskúšaj-chytni-hoď. Už vtedy som pochopil, že to bola nezdravá obchodná logika projektu, takže vždy, keď to bolo možné, som sa snažil takýto dizajn nepoužívať. Poďme však zistiť, prečo je prístup k riešeniu chýb pri takejto konštrukcii zlý. Napísal som malý kód na porovnanie týchto dvoch prístupov a urobil som benchmarky pre každú možnosť.
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;
}
Výsledky v .NET Core 3.0 a Core 2.2 majú podobný výsledok (.NET Core 3.0):
Skúste catch sťažuje pochopenie kódu a predlžuje čas vykonávania vášho programu. Ak však potrebujete tento dizajn, nemali by ste vkladať tie riadky kódu, od ktorých sa neočakáva, že budú spracovávať chyby – kód sa tým uľahčí na pochopenie. V skutočnosti to nie je ani tak spracovanie výnimiek, čo zaťažuje systém, ale skôr vyhadzovanie samotných chýb prostredníctvom novej konštrukcie výnimiek.
Vyhadzovanie výnimiek je pomalšie ako niektoré triedy, ktoré zhromaždia chybu v požadovanom formáte. Ak spracovávate formulár alebo nejaké údaje a jasne viete, v čom by mala byť chyba, prečo to nespracovať?
Nemali by ste písať novú konštrukciu Exception(), ak táto situácia nie je výnimočná. Manipulácia a vyhodenie výnimky je veľmi drahé!!!
Počas mojich 5-ročných skúseností s prácou na platforme .NET som sa stretol s mnohými projektmi, ktoré využívali porovnávanie reťazcov. Videl som aj nasledujúci obrázok: existovalo jedno Enterprise riešenie s mnohými projektmi, z ktorých každý vykonával porovnávanie reťazcov inak. Čo však treba použiť a ako to zjednotiť? V knihe CLR via C# od Richtera som sa dočítal informáciu, že metóda ToUpperInvariant() je rýchlejšia ako ToLowerInvariant().
Úryvok z knihy:
Samozrejme, neveril som tomu a rozhodol som sa vykonať niekoľko testov na .NET Framework a výsledok ma šokoval - viac ako 15% nárast výkonu. Potom, keď som nasledujúce ráno prišiel do práce, ukázal som tieto merania svojim nadriadeným a umožnil som im prístup k zdrojovému kódu. Potom boli 2 zo 14 projektov zmenené tak, aby vyhovovali novým meraniam, a vzhľadom na to, že tieto dva projekty existovali na spracovanie obrovských excelových tabuliek, výsledok bol pre produkt viac než významný.
Predstavujem vám aj merania pre rôzne verzie .NET Core, aby si každý z vás mohol vybrať to najoptimálnejšie riešenie. A chcem len dodať, že vo firme, kde pracujem, používame na porovnávanie reťazcov ToUpper().
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();
}
V .NET Core 3.0 je nárast pre každú z týchto metód ~x2 a vyrovnáva medzi sebou implementácie.
Kompilácia vrstiev
V mojom minulom článku som túto funkcionalitu stručne opísal, rád by som svoje slová poopravil a doplnil. Viacúrovňová kompilácia urýchľuje čas spustenia vášho riešenia, ale obetujete, že časti vášho kódu budú skompilované do optimalizovanejšej verzie na pozadí, čo môže predstavovať malú réžiu. S príchodom NET Core 3.0 sa skrátil čas zostavovania projektov s povolenou kompiláciou vrstiev a boli opravené chyby spojené s touto technológiou. Predtým táto technológia viedla k chybám v prvých požiadavkách v ASP.NET Core a zamrzla počas prvého zostavenia v režime viacúrovňovej kompilácie. V súčasnosti je v .NET Core 3.0 štandardne povolená, ale ak chcete, môžete ju zakázať. Ak ste na pozícii team-leader, senior, middle, alebo ste vedúci oddelenia, potom musíte pochopiť, že rýchly rozvoj projektu zvyšuje hodnotu tímu a táto technológia vám umožní ušetriť čas pre oboch vývojárov. a čas samotného projektu.
.NET o úroveň vyššie
Inovujte svoju verziu .NET Framework / .NET Core. Každá nová verzia často poskytuje ďalšie zvýšenie výkonu a pridáva nové funkcie.
Ale aké sú konkrétne výhody? Pozrime sa na niektoré z nich:
.NET Core 3.0 predstavil obrazy R2R, ktoré skrátia čas spustenia aplikácií .NET Core.
S verziou 2.2 sa objavila Tier Compilation, vďaka ktorej programátori strávia menej času spúšťaním projektu.
Podpora pre nové štandardy .NET.
Podpora novej verzie programovacieho jazyka.
Optimalizácia, s každou novou verziou sa zlepšuje optimalizácia základných knižníc Collection/Struct/Stream/String/Regex a mnoho ďalších. Ak migrujete z .NET Framework na .NET Core, získate veľké zvýšenie výkonu hneď po vybalení. Ako príklad prikladám odkaz na niektoré optimalizácie, ktoré boli pridané do .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/
Záver
Pri písaní kódu sa oplatí venovať pozornosť rôznym aspektom vášho projektu a využívať funkcie vášho programovacieho jazyka a platformy, aby ste dosiahli čo najlepší výsledok. Budem rád, ak sa podelíte o svoje poznatky súvisiace s optimalizáciou v .NET.