Function pointer #скорость
Представим, что у нас есть подсистема вычисления. Один класс отвечает за выбор операции над значениями, а другой производит магию вычисления с использованием выбранной операции. В каждом из классов какая-то сложная логика, поэтому объединить их нельзя или сложно. Пример: операции над формулами в Excel - до того как мы прочитаем формулу, мы не знаем, какая операция будет произведена над ячейками.
Условно, это выглядит вот так:
MathOperation operation = SelectOperation(Context);
Func executor = operation switch {
MathOperation.Add => MathOperations.Add,
MathOperation.Subtract => MathOperations.Subtract,
MathOperation.Multiply => MathOperations.Multiply,
MathOperation.Divide => MathOperations.Divide,
_ => Error.NotSupportedOperation(operation, Context)
};
Calculator.Execute(executor, xValue, yValue);
Это работает быстро, но, благодаря "современному" C# (function pointer'ы появились аж 5 лет назад), подобные сценарии можно ускорить на 20%. Для этого нужно уйти в лёгкий unsafe, и заменить Func на delegate*. Мотивацию появления этого улучшения можно подсмотреть тут.
Этот финт даёт нам возможность выразить следующую мысль: уважаемый компилятор и рантайм, мы точно знаем расположение функции в памяти (указатель), пожалуйста, не трать время, а просто дёрни то, что сказал тебе умный программист.
Для библиотечного кода такой unsafe весьма неплох (так как даёт хороший буст производительности). В случае обычного энтерпрайз кода я бы такое не использовал никогда.
Бенчмарк 'https://t.me/csharp_gepard/160?comment=1937' rel='nofollow'>тут, чтобы каждый мог убедиться, что мы действительно получаем профит.
Представим, что у нас есть подсистема вычисления. Один класс отвечает за выбор операции над значениями, а другой производит магию вычисления с использованием выбранной операции. В каждом из классов какая-то сложная логика, поэтому объединить их нельзя или сложно. Пример: операции над формулами в Excel - до того как мы прочитаем формулу, мы не знаем, какая операция будет произведена над ячейками.
Условно, это выглядит вот так:
MathOperation operation = SelectOperation(Context);
Func executor = operation switch {
MathOperation.Add => MathOperations.Add,
MathOperation.Subtract => MathOperations.Subtract,
MathOperation.Multiply => MathOperations.Multiply,
MathOperation.Divide => MathOperations.Divide,
_ => Error.NotSupportedOperation(operation, Context)
};
Calculator.Execute(executor, xValue, yValue);
Это работает быстро, но, благодаря "современному" C# (function pointer'ы появились аж 5 лет назад), подобные сценарии можно ускорить на 20%. Для этого нужно уйти в лёгкий unsafe, и заменить Func на delegate*. Мотивацию появления этого улучшения можно подсмотреть тут.
Этот финт даёт нам возможность выразить следующую мысль: уважаемый компилятор и рантайм, мы точно знаем расположение функции в памяти (указатель), пожалуйста, не трать время, а просто дёрни то, что сказал тебе умный программист.
Для библиотечного кода такой unsafe весьма неплох (так как даёт хороший буст производительности). В случае обычного энтерпрайз кода я бы такое не использовал никогда.
Бенчмарк 'https://t.me/csharp_gepard/160?comment=1937' rel='nofollow'>тут, чтобы каждый мог убедиться, что мы действительно получаем профит.