1

Is there any difference (performance wise) between:

public User GetUser1()
{
    var user = _database.User.First();
    return user;
}

public User GetUser2()
    return _database.User.First();
}
Anis Alibegić
  • 2,941
  • 3
  • 13
  • 28
  • 2
    The compiler will undoubtedly optimize the variable right out, generating identical IL for both methods. So, to directly answer your question, there is no performance difference between the two. – itsme86 Jul 27 '17 at 23:18
  • And you can see that yourself by converting the compiled executable to text with `ildasm`. See here: https://stackoverflow.com/a/7232029 – Andrew Jul 27 '17 at 23:21
  • 1
    On a side-note: From a debugging perspective, I prefer option 1 since I often look to inspect items while stepping through. – Steve Py Jul 27 '17 at 23:31
  • @itsme86 That's what I wanted to hear. Thank you very much. – Anis Alibegić Jul 27 '17 at 23:47
  • @StevePy Just like me, I always prefer option 1 and that's what I wanted to know, is it bad or not. – Anis Alibegić Jul 27 '17 at 23:47
  • I prefer option 2 but an even easier way to see what is generated is to get LINQPad. @StevePy In the latest VS versions, you can inspect return values. – NetMage Jul 27 '17 at 23:51

1 Answers1

2

Here is the output from LINQPad for C# 7.0 from the same functions on my database:

GetUser1:
IL_0000:  ldarg.0     
IL_0001:  call        LINQPad.User.TypedDataContext.get_Users
IL_0006:  call        System.Linq.Queryable.First<User>
IL_000B:  ret         

GetUser2:
IL_0000:  ldarg.0     
IL_0001:  call        LINQPad.User.TypedDataContext.get_Users
IL_0006:  call        System.Linq.Queryable.First<User>
IL_000B:  ret         

Here is the output with optimization turned off. Note the NOPs and BR.S are for debugging/breakpoint purposes.

GetUser1:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  call        LINQPad.User.TypedDataContext.get_Users
IL_0007:  call        System.Linq.Queryable.First<User>
IL_000C:  stloc.0     // user
IL_000D:  ldloc.0     // user
IL_000E:  stloc.1     
IL_000F:  br.s        IL_0011
IL_0011:  ldloc.1     
IL_0012:  ret         

GetUser2:
IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  call        LINQPad.User.TypedDataContext.get_Users
IL_0007:  call        System.Linq.Queryable.First<User>
IL_000C:  stloc.0     
IL_000D:  br.s        IL_000F
IL_000F:  ldloc.0     
IL_0010:  ret         
NetMage
  • 26,163
  • 3
  • 34
  • 55
  • Say no more. Thank you very much. – Anis Alibegić Jul 27 '17 at 23:54
  • You were faster than I was! – NetMage Jul 27 '17 at 23:56
  • And after you updated your answer, it means that there are two extra instructions. Is it significant? – Anis Alibegić Jul 27 '17 at 23:57
  • Well, that is with optimizations turned off. I see about a 5% performance penalty on running the function 1000 times, which is about 0.05 seconds for the 1000 runs. LOL - running for 6000 times, sometimes one is faster, sometimes the other. Server business and network latency is swamping the differences. It is also possible the JITter is optimizing the IL anyway, so you can't always tell the ultimate efficiency from looking at IL. – NetMage Jul 28 '17 at 00:03
  • Replacing the database call with `DateTime.Now`, I see about a 8% speedup in the second form unoptimized over 10,000,000 calls, for a total of about 0.3 seconds. – NetMage Jul 28 '17 at 00:07