简体   繁体   中英

Which one of these code samples has better performance?

In replies to one of my questions , I received a number of answers saying that style 2 may perform better than style 1. I don't understand how, since I believe they should emit essentially the same machine instructions (if written in C++). Could you please explain why style 2 might perform better?

I'll rewrite the two styles here for easier reference:

Style 1 :

while (!String.IsNullOrEmpty(msg = reader.readMsg()))
{
    RaiseMessageReceived();
    if (parseMsg)
    {
        ParsedMsg parsedMsg = parser.parseMsg(msg);
        RaiseMessageParsed();
        if (processMsg)
        {
            process(parsedMsg);
            RaiseMessageProcessed();
        }
    }
}

Style 2:

while (!String.IsNullOrEmpty(msg = reader.readMsg()))
{
    RaiseMessageReceived();
    if (!parseMsg) continue;

    ParsedMsg parsedMsg = parser.parseMsg(msg);
    RaiseMessageParsed();
    if (!processMsg) continue;

    process(parsedMsg);
    RaiseMessageProcessed();
}

I think performance would be negligibly different if it's different at all. A compiler may optimze them into the same form anyway.

The only substantive difference is stylistic.

I like style 1 just because the loop has one entry point (per iteration) and one exit point (per iteration) so it's easy to insert debug code at the end of the loop and know it'll get called. It's the same principle behind one entry and exit point on functions (for the same reasons). That being said though too much indenting can be hard to read so continue has its place as well.

I had to check this.

Here is my version of the code:

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();
        }
    }
}

I built it with code optimization (default Release configuration), and disassembled the assembly using Reflector. The result verifies that the two styles are identical:

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.");
    }
}

The best answer is to look at the generated byte-code/assembly and see. Then ignore what you see because an optimizing JIT compiler will change it anyway based on real-time analysis of the executing code. So stick with the style that best expresses the intent.

That said, style 2 should jump straight back to the condition, while style 1 could conceivably jump passed the if block only to hit another jump to the condition.

This has to be the best example of when not to prematurely optimize that I have seen.

表现应该是相同的,无论谁说否则一定是......困惑。

为什么不从杰夫的书中抽出一片叶子来计算这个问题中的两段代码呢?

The code flow appears to be identical, and the bytecode should be the same.

Disclaimer: I am a C/C++ programmer, I don't really do C#

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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