Net Performance. Зачем нужна производительность

Содержание

Слайд 2

Зачем нужна производительность?

Зачем нужна производительность?

Слайд 3

Как понять, на каком уровне проблема?

Как понять, на каком уровне проблема?

Слайд 4

Инструменты dotTrace dotMemory BenchmarkDotNet Visual Studio profiler CodeTrack CLR Profiler

Инструменты

dotTrace

dotMemory

BenchmarkDotNet

Visual Studio profiler

CodeTrack

CLR Profiler

Слайд 5

Инструменты BenchmarkDotNet CodeTrack CLR Profiler

Инструменты

BenchmarkDotNet

CodeTrack

CLR Profiler

Слайд 6

Инструменты Performance Monitor

Инструменты

Performance Monitor

Слайд 7

Инструменты ETW Windows Performance Analyzer

Инструменты

ETW
Windows Performance Analyzer

Слайд 8

Инструменты MS Message Analyzer

Инструменты

MS Message Analyzer

Слайд 9

Lock-free & Wait-free

Lock-free & Wait-free

Слайд 10

Lock-free & Wait-free

Lock-free & Wait-free

Слайд 11

Lock-free & Wait-free double CompareExchange (ref double location1, double value, double comparand); Compare and Swap Interlocked

Lock-free & Wait-free

double CompareExchange (ref double location1, double value, double comparand);


Compare and Swap

Interlocked

Слайд 12

ConcurrentDictionary

ConcurrentDictionary

Слайд 13

ConcurrentDictionary Сильная деградация при попытке получить все блокировки

ConcurrentDictionary

Сильная деградация при попытке
получить все блокировки

Слайд 14

SIMD Single instruction, Multiple data float[] values = GetValues(); float increment

SIMD

Single instruction, Multiple data

float[] values = GetValues();
float increment = GetIncrement();
for (int

i = 0; i < values.Length; i++)
{
values[i] += increment;
}

Vector values = GetValues();
Vector increment = GetIncrement();
Vector result = values + increment;

Vector.IsHardwareAccelerated

Слайд 15

SIMD Single instruction, Multiple data

SIMD

Single instruction, Multiple data

Слайд 16

Task.Yield async Task LongRunningCpuBoundWorkAsync() { for (int i = 0; i

Task.Yield

async Task LongRunningCpuBoundWorkAsync()
{
for (int i = 0; i != 1000000;

++i)
{
... // CPU-bound work.
}
}
Слайд 17

Task.Yield async Task LongRunningCpuBoundWorkAsync() { for (int i = 0; i

Task.Yield

async Task LongRunningCpuBoundWorkAsync()
{
for (int i = 0; i != 1000000;

++i)
{
... // CPU-bound work.
await Task.Yield();
}
}
Слайд 18

Long switch-case switch (packetID) { case BncsPacketId.Null: break; case BncsPacketId.EnterChat: string

Long switch-case

switch (packetID)
{
case BncsPacketId.Null:
break;
case BncsPacketId.EnterChat:
string ecUniqueName =

pck.ReadNTString();
string ecStatstring = pck.ReadNTString();
string ecAcctName = pck.ReadNTString();
var args = new EventArgs(ecUniqueName, ecStatstring, ecAcctName);
OnEnteredChat(args);
break; ...
// ну и так и далее
}
Слайд 19

Long switch-case Dictionary > switch (packetID) { case BncsPacketId.Null: break; case

Long switch-case

Dictionary>

switch (packetID)
{
case BncsPacketId.Null:
break;
case BncsPacketId.EnterChat:
string ecUniqueName

= pck.ReadNTString();
string ecStatstring = pck.ReadNTString();
string ecAcctName = pck.ReadNTString();
var args = new EventArgs(ecUniqueName, ecStatstring, ecAcctName);
OnEnteredChat(args);
break; ...
// ну и так и далее
}
Слайд 20

GC Клиентский режим Серверный режим

GC

Клиентский режим

Серверный режим

Слайд 21

ConcurrentBag Оптимизация потребления памяти

ConcurrentBag

Оптимизация потребления памяти

Слайд 22

async/await

async/await

Слайд 23

async/await

async/await

Слайд 24

async/await

async/await

Слайд 25

async/await Task.FromResult(0) Task.CompletedResult .Net 4.6

async/await

Task.FromResult(0)

Task.CompletedResult

.Net 4.6

Слайд 26

Аллокация на стеке .net core 2.1 Span C# 7.2 int* block

Аллокация на стеке

.net core 2.1
Span

C# 7.2
int* block = stackalloc int[100];

Span

span = size <= 128 ? stackalloc byte[size] : new byte[size];

ValueTask

Слайд 27

JIT оптимизация [AggressiveInlining] спасет всех Generic типы инлайнятся Типичные заблуждения: Компилятор

JIT оптимизация

[AggressiveInlining] спасет всех

Generic типы инлайнятся

Типичные заблуждения:

Компилятор умный

internal static class

FreeObjectUtils
{
public void Free(T instance)
where T : IChildItems
{
bool needDispose = typeof(IDisposable).IsAssignableFrom(typeof(T));
foreach (var element in instance.ChildItems) element.Dispose();
if (needDispose)
DisposableUtils.Clean(instance);
else
instance.ChildItems.Clear();
}
}

interface IChildItems
{
Collection ChildItems { get; }
}

Слайд 28

JIT оптимизация [AggressiveInlining] спасет всех Generic типы инлайнятся Типичные заблуждения: Компилятор

JIT оптимизация

[AggressiveInlining] спасет всех

Generic типы инлайнятся

Типичные заблуждения:

Компилятор умный

internal static class

FreeObjectUtils
{
public void Free(T instance)
where T : IChildItems
{
foreach (var element in instance.ChildItems) element.Dispose();
if (false)
DisposableUtils.Clean(instance);
else
instance.ChildItems.Clear();
}
}

interface IChildItems
{
Collection ChildItems { get; }
}

Слайд 29

JIT оптимизация [AggressiveInlining] спасет всех Generic типы инлайнятся Типичные заблуждения: Компилятор

JIT оптимизация

[AggressiveInlining] спасет всех

Generic типы инлайнятся

Типичные заблуждения:

Компилятор умный

internal static class

FreeObjectUtils
{
public void Free(T instance)
where T : IChildItems
{
foreach (var element in instance.ChildItems) element.Dispose();
instance.ChildItems.Clear();
}
}

interface IChildItems
{
Collection ChildItems { get; }
}

Слайд 30

JIT оптимизация public Dictionary(IEqualityComparer comparer); public struct LongEqualityComparer : IEqualityComparer {

JIT оптимизация

public Dictionary(IEqualityComparer comparer);

public struct LongEqualityComparer : IEqualityComparer
{
public static

readonly IEqualityComparer BoxedInstanceInt64 = new LongEqualityComparer();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long x, long y)
{
return x == y;
}
}
Слайд 31

JIT оптимизация [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { if (typeof(T) == typeof(int)

JIT оптимизация

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
if (typeof(T) == typeof(int)

|| typeof(T) == typeof(uint) || typeof(T) == typeof(byte) ||
typeof(T) == typeof(short) || typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
{
_size = 0;
_version++;
}
else
{
int size = (int)_size;
_size = 0;
_version++;
if (size > 0)
Array.Clear(_items, 0, size);
}
}
Слайд 32

MemoryStream

MemoryStream

Слайд 33

MemoryStream

MemoryStream

Слайд 34

MemoryStream То же самое для: List Collection Dictionary и прочих коллекций

MemoryStream

То же самое для:
List
Collection
Dictionary
и прочих коллекций

Слайд 35

struct[] -> IList int[] a = new int[10]; DoSomething(a); public void DoSomething (IList list) { }

struct[] -> IList

int[] a = new int[10];
DoSomething(a);
public void DoSomething(IList list)
{
}

Слайд 36

LINQ // [18 7 - 18 80] IL_000e: ldarg.0 // this

LINQ

// [18 7 - 18 80]
IL_000e: ldarg.0 // this

IL_000f: call instance class [mscorlib]System.Collections.Generic.IEnumerable`1 WpfApp3.Class2::get_AllParts()
IL_0014: ldloc.0 // 'CS$<>8__locals0'
IL_0015: ldftn instance bool WpfApp3.Class2/'<>c__DisplayClass2_0'::'b__0'(class WpfApp3.RibbonPartMetadata)
IL_001b: newobj instance void class [mscorlib]System.Func`2::.ctor(object, native int)
IL_0020: call class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Where(class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Func`2)
IL_0025: call class [mscorlib]System.Collections.Generic.List`1 [System.Core]System.Linq.Enumerable::ToList(class [mscorlib]System.Collections.Generic.IEnumerable`1)
IL_002a: stloc.1 // V_1
IL_002b: br.s IL_002d

public IEnumerable FindChildren(Guid parentId)
{
return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
}

Слайд 37

LINQ public IEnumerable FindChildren(Guid parentId) { return this.AllParts.Where(part => part.ParentGuid ==

LINQ

public IEnumerable FindChildren(Guid parentId)
{
return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
}

public IEnumerable

FindChildren(Guid parentId)
{
var list = new List();
foreach (RibbonPartMetadata part in this.AllParts)
{
if (part.ParentGuid == parentId)
{
list.Add(part);
}
}
return list;
}
Слайд 38

LINQ public IEnumerable FindChildren(Guid parentId) { return this.AllParts.Where(part => part.ParentGuid ==

LINQ

public IEnumerable FindChildren(Guid parentId)
{
return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
}

public IEnumerable

FindChildren(Guid parentId)
{
var list = new List(this.AllPart.Count);
foreach (RibbonPartMetadata part in this.AllParts)
{
if (part.ParentGuid == parentId)
{
list.Add(part);
}
}
return list;
}
Слайд 39

Строки Вместо конкатенаций используй StringBuilder Вместо string.Format используй конкатенацию string first

Строки

Вместо конкатенаций используй StringBuilder

Вместо string.Format используй конкатенацию

string first = "first";

string second = "second";
return $"{first}{second}";

string first = "first";
string second = "second";
return first + second;

Слайд 40

Boxing public void Info(params object[] args) log.Info(1, 2, 3, 4, 5);

Boxing

public void Info(params object[] args)

log.Info(1, 2, 3, 4, 5);

Как надо?
public static

void Info();
public static void Info(T1 arg1);

public static void Info(T1 arg1, T2 arg2, T3 arg3);

static Logger log = new Logger();

log.Info();

new object[0]

Слайд 41

Heap Allocation Viewer

Heap Allocation Viewer

Слайд 42

Почитать? Federico Lois Sasha Goldstein Андрей Акиньшин

Почитать?

Federico Lois
Sasha Goldstein
Андрей Акиньшин