这些代码示例中的哪一个具有更好的性能?
在对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();
}
}
}
款式二:
while (!String.IsNullOrEmpty(msg = reader.readMsg()))
{
RaiseMessageReceived();
if (!parseMsg) continue;
ParsedMsg parsedMsg = parser.parseMsg(msg);
RaiseMessageParsed();
if (!processMsg) continue;
process(parsedMsg);
RaiseMessageProcessed();
}
我不得不检查。
这里是我的代码版本:
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();
}
}
}
我用代码优化(默认发布配置)建立了它,并使用反射拆卸组装。 结果验证了这两种风格是相同的:
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.");
}
}
性能应该是相同的,无论是谁否则一定会......困惑。
最好的答案是查看生成的字节码/程序集并查看。然后忽略你所看到的,因为优化的JIT编译器会根据对执行代码的实时分析来改变它。所以坚持最能表达意图的风格。
也就是说,风格2应该直接跳回到条件,而风格1可以想象跳过if块只是再次跳转到条件。
这不得不过早地优化我所见过的最好例子。
为什么不从杰夫的书中抽出一小段代码,如this question?
我的问题具有更多的理论性质,所以时间不是我正在寻找的。我担心的是,如果代码是用C++编写的,那么这个代码会(在理论上)被编译到相同的程序集中,所以我担心它是否与C#不一样? – 2009-01-01 08:44:36
@Hosma Aly,我不明白。你想知道什么效果更好,但时间不是你想要的? – tuinstoel 2009-01-01 13:39:19
我认为如果性能完全不同,性能可以忽略不计。无论如何,编译器可能会将它们优化为相同的形式。
唯一的实质性差异是文体。
我喜欢style 1只是因为循环有一个入口点(每次迭代)和一个出口点(每次迭代),所以很容易在循环结尾插入调试代码并知道它会被调用。在一个函数的入口和出口点背后是相同的原理(出于同样的原因)。尽管如此,缩进可能很难阅读,所以继续也有它的位置。
代码流看起来是相同的,字节码应该是相同的。
免责声明:我是一个C/C++程序员,我不会做C#
其实这个问题既不是关于风格,也没有优化。风格在我之前的问题中已经讨论过了,我知道在这种情况下优化是无关紧要的。但是我想知道编译器/ JIT的实际输出。 – 2009-01-01 08:48:58
您可能没有明确地这么说,但是当您询问A是否会比B更好地执行时,您正在询问优化问题。哪两种类似替代方案的性能最佳? – 2009-01-02 07:05:26