【问题标题】:Why is Console.WriteLine speeding up my application?为什么 Console.WriteLine 会加速我的应用程序?
【发布时间】:2014-07-20 19:53:50
【问题描述】:

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

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

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

Console.WriteLine(palindrome.ToString());

对于每次寻找回文的迭代,我的运行时间从 ~24 到 ~14 下降了惊人的 10 秒。

为了验证,我运行了几次程序,然后注释掉了控制台命令并运行了几次,每次都更短使用控制台命令。

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

如果有人想试一试,这里是来源:

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

【问题讨论】:

  • 你的测量结果如何?
  • 是在调试模式还是在发布模式下运行?什么 .NET 版本?你测量这个吗?您没有显示该度量的代码。
  • 这确实是一个很大的猜测:可能是因为您正在写入 IO,您的线程会获得更多的处理器时间,因为 WriteLine 是同步的,因此会阻塞其他线程。
  • 用函数调用编辑。谢谢!
  • @ForguesR 好主意!很可能就是这样。不过看起来还是很奇怪

标签: c# algorithm console performance


【解决方案1】:

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

调试构建,无论是否使用控制台 Writeline 语句(是否注释掉),是否处于调试模式,时间从大约 8.7 秒到 9.8 秒不等。作为一个发布版本,它下降到大约 6.8-7.0 秒。 VS 内部和命令行中的数字相同。所以你的观察没有被复制。

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

根据我的判断,您带有控制台输出的数字可能与我的一致,并且代表了真实值。所以你的问题应该是:为什么你的系统在不做控制台输出的时候会这么慢?

答案是:因为您的计算机或您的项目有一些我们不知道的不同之处。我以前从未见过这种情况,但有些东西正在吸收周期,你应该能够找出它是什么。

我把它写成一个答案,虽然它不是一个真正的答案。如果您获得更多事实并更新您的问题,希望我能提供更好的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    相关资源
    最近更新 更多