为什么Console.WriteLine会加速我的应用程序?

时间:2014-05-30 23:59:57

标签: c# algorithm console performance

好的,这有点奇怪。我有一个算法来找到最高可能的数值回文,它是两个因子的倍数,每个因子都有K个数字。

用于找到最高有效回文的方法是查看数字集的最高可能回文(即,如果k = 3,则最高可能是999999,然后是998899等)。然后我检查回文是否有两个K位数因子。

对于调试,我认为将每个我正在检查的回文打印到控制台是个好主意(以确保我得到它们。令我惊讶的是,添加

Console.WriteLine(palindrome.ToString());

每次迭代找到一个回文都会使我的运行时间从大约24秒减少到大约10秒~14。

要验证,我多次运行该程序,然后注释掉Console命令并运行了几次,每次使用控制台命令时更短

这看起来很奇怪,有什么想法吗?

如果有人想对此进行打击,那么这就是来源:

    static double GetHighestPalindromeBench(int k)
    {
        //Because the result of k == 1 is a known quantity, and results in aberrant behavior in the algorithm, handle as separate case
        if (k == 1)
        {
            return 9;
        }


        /////////////////////////////////////
        //These variables will be used in HasKDigitFactors(), no need to reprocess them each time the function is called
        double kTotalSpace = 10;

        for (int i = 1; i < k; i++)
        {
            kTotalSpace *= 10;
        }

        double digitConstant = kTotalSpace;  //digitConstant is used in HasKDigits() to determine if a factor has the right number of digits

        double kFloor = kTotalSpace / 10; //kFloor is the lowest number that has k digits (e.g. k = 5, kFloor = 10000)

        double digitConstantFloor = kFloor - digitConstant;  //also used in HasKDigits()

        kTotalSpace--;  //kTotalSpace is the highest number that has k digits (e.g. k = 5, kTotalSpace = 99999)

        /////////////////////////////////////////


        double totalSpace = 10;

        double halfSpace = 10;

        int reversionConstant = k;

        for (int i = 1; i < k * 2; i++)
        {
            totalSpace *= 10;
        }

        double floor = totalSpace / 100;

        totalSpace--;


        for (int i = 1; i < k; i++)
        {
            halfSpace *= 10;
        }

        double halfSpaceFloor = halfSpace / 10;    //10000

        double halfSpaceStart = halfSpace - 1;     //99999

        for (double i = halfSpaceStart; i > halfSpaceFloor; i--)
        {
            double value = i;
            double palindrome = i;
            //First generate the full palindrome
            for (int j = 0; j < reversionConstant; j++)
            {
                int digit = (int)value % 10;

                palindrome = palindrome * 10 + digit;

                value = value / 10;
            }

            Console.WriteLine(palindrome.ToString());
            //palindrome should be ready
            //Now we check the factors of the palindrome to see if they match k
            //We only need to check possible factors between our k floor and ceiling, other factors do not solve
            if (HasKDigitFactors(palindrome, kTotalSpace, digitConstant, kFloor, digitConstantFloor))
            {
                return palindrome;
            }
        }


        return 0;
    }

    static bool HasKDigitFactors(double palindrome, double totalSpace, double digitConstant, double floor, double digitConstantFloor)
    {
        for (double i = floor; i <= totalSpace; i++)
        {
            if (palindrome % i == 0)
            {
                double factor = palindrome / i;
                if (HasKDigits(factor, digitConstant, digitConstantFloor))
                {
                    return true;
                }
            }
        }
        return false;
    }

    static bool HasKDigits(double value, double digitConstant, double digitConstantFloor)
    {
        //if (Math.Floor(Math.Log10(value) + 1) == k)
        //{
        //    return true;
        //}
        if (value - digitConstant > digitConstantFloor && value - digitConstant < 0)
        {
            return true;
        }

        return false;
    }

请注意,我在HasKDigits中注释了Math.Floor操作。当我试图确定我的数字检查操作是否比Math.Floor操作更快时,这一切都开始了。谢谢!

编辑:函数调用

我使用StopWatch来测量处理时间。我还使用物理秒表来验证StopWatch的结果。

        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        double palindrome = GetHighestPalindromeBench(6);
        stopWatch.Stop();

        TimeSpan ts = stopWatch.Elapsed;

        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}:{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

        Console.WriteLine();
        Console.WriteLine(palindrome.ToString());
        Console.WriteLine();
        Console.WriteLine(elapsedTime);

1 个答案:

答案 0 :(得分:4)

我已经测试了你的代码。我的系统是i7-3770 3.40 GHz,具有超线程的四核,因此可以使用8个内核。

使用和不使用控制台Writeline语句(已注释或未注释)的调试版本,无论是否在调试模式下,时间从大约8.7秒到9.8秒不等。作为发布版本,无论哪种方式都可以达到大约6.8-7.0秒。 VS内部和命令行中的数字相同。所以你的观察不会再现。

在没有控制台输出的性能监视器上,我看到一个核心为100%,但它在核心1,4,5和8之间切换。没有控制台输出,其他核心上就有活动。最大CPU使用率永远不会超过18%。

根据我的判断,你的控制台输出数字可能与我的一致,并代表真正的价值。所以你的问题应该是:为什么你的系统在没有控制台输出的情况下这么慢?

答案是:因为您的计算机或项目存在一些我们不了解的不同之处。我之前从未见过这个,但是有些东西正在吸收循环,你应该能够找到它是什么。

我已经写过这个作为答案,虽然它不是一个真正的答案。如果你得到更多的事实并更新你的问题,希望我能提供更好的答案。