简体   繁体   English

C# 6.0 “string” 和 $“string” 之间的性能差异

[英]Performance difference between C# 6.0 “string” and $“string”

I have 2 codes in C# 6.0:我在 C# 6.0 中有 2 个代码:

Sample 1:示例 1:

string bar;
// ... some code setting bar.
var foo =
    "Some text, " +
    $"some other {bar}, " +
    "end text.";

Sample 2:示例 2:

string bar;
// ... some code setting bar.
var foo =
    $"Some text, " +
    $"some other {bar}, " +
    $"end text.";

Obviously both codes generate the same result regardless of aesthetic differences.显然,无论审美差异如何,两种代码都会产生相同的结果。

Question:问题:
Is there a performance difference between both?两者之间有性能差异吗? In other words, are both cases compiled to the same?换句话说,两种情况都编译为相同的吗?

EDIT:编辑:
Some important comments was posted that I find useful to replay to make a clarification of the topic in this question.发布了一些重要的评论,我发现重播这些评论对澄清此问题中的主题很有用。

The second one is horrible.第二个太可怕了。 Don't use the string interpolation symbol ($) on strings that aren't interpolated.不要在未插值的字符串上使用字符串插值符号 ($)。 It will be confusing for anyone else looking at the code (or future, more experienced you)对于查看代码的其他人(或将来,更有经验的您)来说,这会令人困惑

Thanks for the tip, it's very appreciated, although I have to argue that what you said is a aesthetic argumentation.感谢您的提示,非常感谢,尽管我不得不争辩说您所说的是一种美学论证。 Even this code been as ugly as you said, even if should never been used, I still think is useful discuss possible performances differences that It MAY generated.即使这段代码像你说的一样丑陋,即使不应该被使用,我仍然认为讨论它可能产生的可能的性能差异是有用的。

@communityMember1: It doesn't affect performance of the code at runtime. @communityMember1:它不会影响运行时代码的性能。
@communityMember2: That is not true. @communityMember2:这不是真的。 Interpolated string is syntactic sugar for calling string.Format, which has to be called (and thus affecting performance).内插字符串是调用 string.Format 的语法糖,它必须被调用(从而影响性能)。

Maybe to avoid further discussion, we should reinforce the answers and comments based on some documentation or even an empirical proof (like the result of a compilation).也许为了避免进一步的讨论,我们应该根据一些文档甚至经验证明(如汇编的结果)来加强答案和评论。

The $ creates an interpolated string which is the same as using String.Format . $创建一个与使用String.Format相同的内插字符串。 If you use + with string literals then the compiler optimizes the code to avoid concatenation all together.如果将+与字符串文字一起使用,则编译器会优化代码以避免将所有连接在一起。 The use of interpolated strings might prevent this optimization.使用内插字符串可能会阻止这种优化。

Edit编辑


Performance and Literal Optimization Test性能和文字优化测试

Ok, well I just tested this and there doesn't seem to be any performance issue.好吧,我刚刚对此进行了测试,似乎没有任何性能问题。 Apparently the compiler ignores $ and doesn't use String.Format if no {} are present.显然,如果不存在{} ,编译器会忽略$并且不使用 String.Format。 My test results are shown below for 6 million loops of constructing a 50 length string.我的测试结果如下所示,用于构建 50 长度的字符串的 600 万次循环。

  • String.Format : 23700 ms String.Format :23700 毫秒
  • $"a{null}" with + : 22650 ms $"a{null}"+ :22650 毫秒
  • $"a" with + : 13 ms $"a"+ :13 毫秒
  • "a" with + : 13 ms "a"+ :13 毫秒
  • "a" concatenated with + : 700 ms "a"+连接:700 毫秒

Also, there's no difference looking at the IL.此外,查看 IL 也没有区别。 So performance wise, the code you posted is executed and optimized the same, the $ gets ignored and is only a factor when {} are used.因此在性能方面,您发布的代码的执行和优化相同, $被忽略并且仅在使用{}时是一个因素。

Syntax语法

Of course there can be debate about if that is good syntax or not.当然,这是否是好的语法可能存在争议。 I can think of arguments for and against.我能想到支持和反对的论据。

Pros优点

  • It's easier to add a new argument if $ is already present如果$已经存在,添加新参数会更容易
  • It's easier to move an argument between lines of a multi-line literal在多行文字的行之间移动参数更容易
  • It provides consistency between lines of a multi-line literal它提供了多行文字的行之间的一致性

Cons缺点

  • It looks different... principal of least astonishment.看起来不一样了……最少惊讶的原则。
  • Why add syntax that isn't being used?为什么要添加未使用的语法?
  • It doesn't make the inserted variable obvious它不会使插入的变量显而易见

For me, the tilting point is that I see $ and expect to see a {} and an argument.对我来说,倾斜点是我看到$并希望看到一个{}和一个参数。 It causes cognitive dissonance if I don't see what I expect to see.如果我没有看到我期望看到的东西,就会导致认知失调。 On the other hand, I can imagine situations where the fluidity it provides might out way this.另一方面,我可以想象它提供的流动性可能会解决这个问题的情况。 It's probably far to say it depends on the development group and objectives.说这取决于开发组和目标可能还很遥远。

Look at the IL:看看IL:

First code:第一个代码:

var bar = "a";
var foo = "b" + $"{bar}";

First IL:第一个 IL:

IL_0000:  nop         
IL_0001:  ldstr       "a"
IL_0006:  stloc.0     // bar
IL_0007:  ldstr       "b"
IL_000C:  ldstr       "{0}"
IL_0011:  ldloc.0     // bar
IL_0012:  call        System.String.Format
IL_0017:  call        System.String.Concat
IL_001C:  stloc.1     // foo
IL_001D:  ret         

Second code:第二个代码:

var bar = "a";
var foo = $"b" + $"{bar}";

Second IL:第二个IL:

IL_0000:  nop         
IL_0001:  ldstr       "a"
IL_0006:  stloc.0     // bar
IL_0007:  ldstr       "b"
IL_000C:  ldstr       "{0}"
IL_0011:  ldloc.0     // bar
IL_0012:  call        System.String.Format
IL_0017:  call        System.String.Concat
IL_001C:  stloc.1     // foo
IL_001D:  ret         

Conclusion:结论:

There is no compiled differences between the both codes.两个代码之间没有编译差异。

PS: (IL generated by Linqpad 5.22.02). PS:(由 Linqpad 5.22.02 生成的 IL)。

This was pretty easy to do some simple diagnostics with.这很容易进行一些简单的诊断。 Maccettura shows in the comment that that there is no difference when it gets compiled as it only called String.Format once for each string regardless of the extra interpolation but this test will back it up as well. Maccettura 在评论中显示它在编译时没有区别,因为它只为每个字符串调用一次 String.Format 而不管额外的插值,但这个测试也会支持它。

int rounds = 50;
int timesToCreateString = 50000;
Stopwatch sw = new Stopwatch();
double first = 0;
double second = 0;
for (int i = 0; i < rounds; i++)
{
    sw.Start();
    for (int bar = 0; bar < timesToCreateString; bar++)
    {
        var foo = "Some text, " +
                 $"some other {bar}, " +
                  "end text.";
    }
    sw.Stop();
    first += sw.ElapsedTicks;
    sw.Reset();
    sw.Start();
    for (int bar = 0; bar < timesToCreateString; bar++)
    {                
        var foo = $"Some text, " +
                  $"some other {bar}, " +
                  $"end text.";
    }
    sw.Stop();
    second += sw.ElapsedTicks;
    sw.Reset();
}
Console.WriteLine("Average first test: " + first / rounds);
Console.WriteLine("Average second test: " + second / rounds);
Console.ReadKey();
// program ran 3 times and results.
//Average first test: 54822.04
//Average second test: 55083.86

//Average first test: 54317.66
//Average second test: 54807.8

//Average first test: 49873.12
//Average second test: 48264.36

You can choose whatever you like.你可以选择任何你喜欢的。 It is true the $ translates to string.format (see https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interpolated-strings ) but the compiler is smart enough to filter out code that isn't formatted.确实 $ 转换为 string.format(请参阅https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interpolated-strings )但编译器足够聪明,可以过滤掉代码那不是格式化的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM