2016-09-19 4 views
2

Предположит, у вас есть такие C# код:Можно ли сделать inlining в C#, который оптимизирует конкатенацию строк?

const string ABC = "ABC"; 
const string XYZ = "XYZ"; 

var result = ABC + ":" + XYZ; 

Такого код оптимизирован компилятором, так что у вас есть одна постоянной строка «ABC: XYZ» в переменном результате, вместо того, чтобы делать фактическую конкатенацию 3 строк во время выполнения.

Теперь я хочу, чтобы ввести вспомогательную функцию, которая будет скрывать, что конкатенация от пользователей (чтобы сделать код более надежным и менее подвержены ошибкам):

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
    static string Combine(string first, string second) => first + ":" + second; 

const string ABC = "ABC"; 
const string XYZ = "XYZ"; 

var result = Combine(ABC, XYZ); 

В этом случае я вижу, что этот метод фактически встраиваемые в вызывающем методе, но при разборке я четко вижу, что он вызывает string.Concat(string a, string b, string c) во время выполнения, вместо того, чтобы иметь один постоянный строковый литерал «ABC: XYZ».

Я понимаю, что во время компиляции есть баланс между скоростью и качеством, но есть ли какой-либо трюк, чтобы метод Combine работал как макрос C++, чтобы избежать избыточных конкатенаций строк во время выполнения?

P.S. введение статических строк readonly, которые вычисляются один раз, не является ответом на вопрос.

+0

Почему вы не можете просто использовать функцию string.Concat().? – MethodMan

+0

, потому что он медленный, мне нужно производительность –

+0

запуск его на основе вашего примера с моего конца не замедляется при wll .. как насчет метода string.Join() then .. – MethodMan

ответ

3

Полезно понять подсказку MethodImplOptions.AggressiveInlining и о том, о чем она предназначена и для чего она полезна.

Я понимаю, что метод встраивание (будь то намекал/пожелал программистом, чтобы быть сделано агрессивно или нет) - это все о сайты вызова (то есть, в вашем случае, о «кем/где» Ваше Комбинат называется), но не о том, что в противном случае представляет собой тело (возможно, встроенного) метода.

Другими словами, когда вы рефакторинг ваше выражение

... ABC + ":" + XYZ ... 

(что именно "идеальный"/номинальный кандидат на постоянной оптимизации складной, очевидно)

в

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
static string Combine(string first, string second) => first + ":" + second 

и затем

(на площадке для звонков)

... Combine(ABC, XYZ) ... 

вы действительно «сказал» что-то совсем другое, чтобы компилятор:

«Я хочу статический метод, который принимает две строки и возвращает третий, я хочу назвать его в этом месте вызова прямо здесь, о, и, пожалуйста, попробуйте вставить это для меня."

Потому что в вашем случае комбинация - это чистая, нерекурсивная функция, которая ничего не делает с стеком вызовов, который нельзя переписать« на месте », где бы он не вызывался с фактическими аргументами (будь то эти константы или нет), это это действительно возможно встраивать его вызов, - но это еще ничего не говорит о том, что другие, дополнительные оптимизации могут быть возможными надтела зерноуборочного методом самого, здесь эквивалентно (после лямбдой desugaring)

return first + ":" + second; 

(и таким образом составлен как

return string.Concat(first, second); 

как вы заметили)

В конце концов, что, если другие части вашего кода имеет логику, которая зависит от отражающего (через функциональные возможности System.Reflection в) над ним? Он все еще должен быть объявлен как член где-то и иметь тело, прикрепленное к нему, нет? (опять же, может ли он быть «бонусом» или «нет» и т. д.)

Оттуда «тело, прикрепленное к нему» подразумевает, что в CIL должен быть один и один, выраженный в CIL/MSIL и т. Д.

Вот как я вижу этот метод [MethodImpl (MethodImplOptions.AggressiveInlining)] в вашем методе Combine как простой намек: «эй, пожалуйста, давайте избежим единственного, глупого фрейма кадра здесь и там, чтобы позвонить Объединяй, когда сможешь. - и ничего кроме этого.

+0

Спасибо за ответ. Я не понимаю, почему он занижен - это законный вопрос оптимизации компилятора, который публикуется в соответствии с рекомендациями StackOverflow. Мне просто интересно, возможно ли заставить компилятор оптимизировать тело вызывающего абонента с помощью метода (-ов) введенных методов. Я предполагаю, что ответ отрицательный, но надеемся, что гуру компилятора с точкой-точкой столкнется с этим вопросом и может подтвердить такое предположение. –

0

Это можно сделать, используя ткачество во время компиляции. Идея здесь в том, что вы найдете все сайты вызовов для своего метода (не встраивайте их!) И замените их во время компиляции с помощью кодов операций ldtoken с конкатенированной строкой в ​​качестве операнда.

Эти инструменты будут полезны для достижения вашей цели.

• PostSharp • Aspect.NET. Опирается на Феникс. • AspectDNG. Опирается на Сесил. • ComposeStar/StarLight • Gripper Loom.NET • Phx.Morph/Wicca. Опирается на Феникс.