在对one of my questions的回复中,我收到了一些答案,说样式2可能比样式1表现更好。我不明白怎么样,因为我认为它们应该发出基本相同的机器指令(如果写的话)在C ++)。你能解释为什么风格2可能表现更好吗?
我会在这里重写这两种风格以便于参考:
样式1 :
while (!String.IsNullOrEmpty(msg = reader.readMsg()))
{
RaiseMessageReceived();
if (parseMsg)
{
ParsedMsg parsedMsg = parser.parseMsg(msg);
RaiseMessageParsed();
if (processMsg)
{
process(parsedMsg);
RaiseMessageProcessed();
}
}
}
样式2:
while (!String.IsNullOrEmpty(msg = reader.readMsg()))
{
RaiseMessageReceived();
if (!parseMsg) continue;
ParsedMsg parsedMsg = parser.parseMsg(msg);
RaiseMessageParsed();
if (!processMsg) continue;
process(parsedMsg);
RaiseMessageProcessed();
}
答案 0 :(得分:10)
如果它完全不同,我认为表现会有不同的差别。无论如何,编译器可以将它们优化为相同的形式。
唯一的实质性区别是风格。
我喜欢样式1只是因为循环有一个入口点(每次迭代)和一个出口点(每次迭代)所以很容易在循环结束时插入调试代码并知道它将被调用。这与函数的一个入口和出口点背后的原理相同(出于同样的原因)。尽管如此,虽然太多的缩进可能难以阅读,所以继续也有它的位置。
答案 1 :(得分:4)
我必须检查一下。
这是我的代码版本:
using System;
using System.Collections.Generic;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Tester t=new Tester();
t.Method1(new Stack<string>(), new MsgParser(), true, true);
t.Method2(new Stack<string>(), new MsgParser(), true, true);
}
}
class Tester
{
public void Method1(Stack<string> strings, MsgParser parser, bool parseMsg, bool processMsg)
{
string msg;
while (!String.IsNullOrEmpty(msg = strings.Pop()))
{
RaiseMessageReceived();
if (parseMsg)
{
ParsedMsg parsedMsg = parser.ParseMsg(msg);
RaiseMessageParsed();
if (processMsg)
{
process(parsedMsg);
RaiseMessageProcessed();
}
}
}
}
public void Method2(Stack<string> strings, MsgParser parser, bool parseMsg, bool processMsg)
{
string msg;
while (!String.IsNullOrEmpty(msg = strings.Pop()))
{
RaiseMessageReceived();
if (!parseMsg) continue;
ParsedMsg parsedMsg = parser.ParseMsg(msg);
RaiseMessageParsed();
if (!processMsg) continue;
process(parsedMsg);
RaiseMessageProcessed();
}
}
private void RaiseMessageProcessed()
{
Console.WriteLine("Done");
}
private void process(ParsedMsg msg)
{
Console.WriteLine(msg);
}
private void RaiseMessageParsed()
{
Console.WriteLine("Message parsed");
}
private void RaiseMessageReceived()
{
Console.WriteLine("Message received.");
}
}
internal class ParsedMsg
{
}
internal class MsgParser
{
public ParsedMsg ParseMsg(string msg)
{
return new ParsedMsg();
}
}
}
我使用代码优化(默认版本配置)构建它,并使用Reflector反汇编程序集。 结果验证两种样式是否相同:
internal class Tester
{
// Methods
public void Method1(Stack<string> strings, MsgParser parser, bool parseMsg, bool processMsg)
{
string msg;
while (!string.IsNullOrEmpty(msg = strings.Pop()))
{
this.RaiseMessageReceived();
if (parseMsg)
{
ParsedMsg parsedMsg = parser.ParseMsg(msg);
this.RaiseMessageParsed();
if (processMsg)
{
this.process(parsedMsg);
this.RaiseMessageProcessed();
}
}
}
}
public void Method2(Stack<string> strings, MsgParser parser, bool parseMsg, bool processMsg)
{
string msg;
while (!string.IsNullOrEmpty(msg = strings.Pop()))
{
this.RaiseMessageReceived();
if (parseMsg)
{
ParsedMsg parsedMsg = parser.ParseMsg(msg);
this.RaiseMessageParsed();
if (processMsg)
{
this.process(parsedMsg);
this.RaiseMessageProcessed();
}
}
}
}
private void process(ParsedMsg msg)
{
Console.WriteLine(msg);
}
private void RaiseMessageParsed()
{
Console.WriteLine("Message parsed");
}
private void RaiseMessageProcessed()
{
Console.WriteLine("Done");
}
private void RaiseMessageReceived()
{
Console.WriteLine("Message received.");
}
}
答案 2 :(得分:3)
最好的答案是查看生成的字节码/汇编并查看。然后忽略你看到的内容,因为优化的JIT编译器无论如何都会根据执行代码的实时分析来改变它。所以坚持最能表达意图的风格。
那就是说,样式2应该直接跳回到条件,而样式1可以想象跳过if块只是为了再次跳到条件。
这必须是不过早优化我所见过的最好的例子。
答案 3 :(得分:0)
表现应该是相同的,否则谁说的一定是......困惑。
答案 4 :(得分:0)
为什么不从杰夫的书中抽出一片叶子来计算this question中的两段代码呢?
答案 5 :(得分:0)
代码流似乎相同,字节码应该相同。
免责声明:我是C / C ++程序员,我不是真的做C#