控制台应用中的奇怪问题

时间:2012-03-08 16:44:03

标签: c# console

编辑:在得到五个downvotes但没有任何评论说明为什么之后,我试图重新表述这个问题。我只能假设投票是因为人们看到很多文字,也许认为这里甚至没有问题。

我编写的代码(mis)行为相当奇怪。似乎代码在其他计算机上的运行方式不同,所以如果你不能重现这个问题,请不要生我的气。

我只是为了好玩,看看GUID中出现不同字节的频率。我注意到guids的字符串表示总是包含“4”。我没有在维基百科上阅读它,而是试着思考它可能是什么,因为做一些“原创研究”并偶尔做自己的想法会很有趣。 (之后再阅读wiki!)

当我尝试使用“爆发”功能时,我的机器上出现了一个奇怪的问题。如果它在您的环境中是可重现的,您可以通过运行应用程序并按B来重新创建它。这应该会导致100个步骤的爆发(即制作100个新的guid,仅在结束时更新显示的频率爆裂,因为写入控制台是如此可笑的慢)。但它实际上只是一步!

我在ProcessKey()中设置了一个断点,其中分配了突发变量。当我退出方法时,我会在Debug Output中注意到一个线程退出。这不是巧合;它每次都可靠地发生。然后我的手表向我显示上一步中刚刚分配给1000的突发变量...值为0。

为什么会这样?我做错什么了吗?我注意到在任何地方都没有指定STA的属性,但我从来没有真正知道这些东西到底是什么,我没有从我使用的控制台应用程序模板中删除任何东西(使用VS-2011开发人员预览版,虽然​​不像Redmond I现在住在2012年)...

最后:应用程序将光标向后移动并反复覆盖文本。如果您无法使控制台窗口足够高以同时显示所有输出,那么这可能无法正常工作,因此您可能想要调整控制台字体(或更改控制台的宽度,应用程序应相应更改我没有测试过)。模式变得完全正常(至少在我的机器上!),带有4列输出(如果你的控制台是80个字符宽,你将获得4列)。

重现的代码(视情况而定):

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static bool running, exit;
        static int burst;
        static long guidCount = 0;
        static long[] counts = new long[256];
        static DateTime nextReport = DateTime.MinValue;
        static readonly TimeSpan reportInterval = TimeSpan.FromSeconds(0.25);


        static void Main(string[] args)
        {
            Console.WindowHeight = (int)(0.8*Console.LargestWindowHeight);

            WriteLine(ConsoleColor.White, "X - Exit | P - Pause | S - Step (hold for Slow) | B - Burst\r\n");
            WriteLine("Auto-reporting interval = {0}.", reportInterval);

            Guid guid;
            byte[] bytes;

            var cursorPos = new CursorLocation();

            while (!exit)
            {
                if (Console.KeyAvailable)
                {
                    ProcessKey(Console.ReadKey(true));
                }

                if (running || burst > 0)
                {
                    guid = Guid.NewGuid();
                    bytes = guid.ToByteArray();
                    ++guidCount;

                    for (int i = 0; i < 16; i++)
                    {
                        var b = bytes[i];
                        ++counts[b];
                    }

                    if (burst > 0) --burst;

                    if (burst == 0 || DateTime.Now > nextReport)
                    {
                        burst = -1;
                        cursorPos.MoveCursor();
                        ReportFrequencies();
                    }
                }
                else
                    Thread.Sleep(20);
            }
        }


        static void ProcessKey(ConsoleKeyInfo keyInfo)
        {
            switch (keyInfo.Key)
            {
                case ConsoleKey.P:
                    running = !running;
                    break;

                case ConsoleKey.B:
                    burst = 100;
                    break;

                case ConsoleKey.S:
                    burst = 1;
                    break;

                case ConsoleKey.X:
                    exit = true;
                    break;
            }
        }


        static void ReportFrequencies()
        {
            Write("\r\n{0} GUIDs generated. Frequencies:\r\n\r\n", guidCount);

            const int itemWidth = 9;
            int colCount = Console.WindowWidth / (itemWidth*2);

            for (int i = 0; i < 256; i++)
            {
                var f = (double)counts[i] / (16 * guidCount);
                Write(RightAdjust(itemWidth, "{0:x}", i));
                Write(GetFrequencyColor(f), " {0:p}".PadRight(itemWidth), f);
                if ((i + 1) % colCount == 0) Write("\r\n");
            }

            nextReport = DateTime.Now + reportInterval;
        }


        static ConsoleColor GetFrequencyColor(double f)
        {
            if (f < 0.003) return ConsoleColor.DarkRed;
            if (f < 0.004) return ConsoleColor.Green;
            if (f < 0.005) return ConsoleColor.Yellow;
            return ConsoleColor.White;
        }


        static string RightAdjust(int w, string s, params object[] args)
        {
            if (args.Length > 0)
                s = string.Format(s, args);
            return s.PadLeft(w);
        }

        #region From my library, so I need not include that here...
        class CursorLocation
        {
            public int X, Y;
            public CursorLocation()
            {
                X = Console.CursorLeft;
                Y = Console.CursorTop;
            }

            public void MoveCursor()
            {
                Console.CursorLeft = X;
                Console.CursorTop = Y;
            }
        }


        static public void Write(string s, params object[] args)
        {
            if (args.Length > 0) s = string.Format(s, args);
            Console.Write(s);
        }


        static public void Write(ConsoleColor c, string s, params object[] args)
        {
            var old = Console.ForegroundColor;
            Console.ForegroundColor = c;
            Write(s, args);
            Console.ForegroundColor = old;
        }


        static public void WriteNewline(int count = 1)
        {
            while (count-- > 0) Console.WriteLine();
        }


        static public void WriteLine(string s, params object[] args)
        {
            Write(s, args);
            Console.Write(Environment.NewLine);
        }


        static public void WriteLine(ConsoleColor c, string s, params object[] args)
        {
            Write(c, s, args);
            Console.Write(Environment.NewLine);
        }
        #endregion
    }
}

1 个答案:

答案 0 :(得分:1)

Ehem。我尝试在我的HTPC上运行代码,这是与我编写的计算机不同的计算机,现在我无法重现问题。也就是说,我确实观察到突发只是一步,但这是由于我的代码中的逻辑错误(当达到报告间隔时,它将突发设置为-1)。很难相信我做了没有设置我的断点,走过去,看到变量被破坏了,因为我知道会有多奇怪,并且多次尝试以确保我看到了我认为我看到的。但是我也很难相信我在框架/ clr中偶然发现了这样一个奇怪而深刻的错误,特别是考虑到我的代码有一个错误会导致让我首先附加调试器的错误。

无论如何,我会将其标记为已关闭。如果有人想玩它,可以在这里发布修改后的代码。我已经修复了这个错误并使输出更加紧凑,所以它在不那么宽大的屏幕上效果比22英寸全HD_one我做的更好。它现在使用8列而不管控制台宽度,可能是安全的假设大多数人使用标准的80字符宽度,现在适合8列。

如果有人愿意运行这个并发布他们的发现(只需按P即可快速获得稳定的频率,步骤/爆发的事情就像傻事一样,看看经过更少代后分布的样子)。在我的HTPC上,我得到了这个结果:

0x00 - 0x3f  0.34%
0x40 - 0x4f  0.73%
0x50 - 0x7f  0.34%
0x80 - 0xbf  0.44%
0xc0 - 0xff  0.34%

这意味着:字节0x00到0x3f各占所有生成的guid中所有字节的0.34%(在这种特殊情况下为509,194,但我每次都得到这个结果超过100,000个guid左右)。有3个非常不同的小组,也许如果我现在去了解维基百科上的Guids,我会理解为什么会这样。但如果我的“发现”是我在开始之前所知道的事情,那么这样做并不会那么有趣。 :)

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static bool running, exit;
        static int burst;
        static long guidCount = 0;
        static long[] counts = new long[256];
        static DateTime nextReport = DateTime.MinValue;
        static readonly TimeSpan reportInterval = TimeSpan.FromSeconds(1);


        static void Main(string[] args)
        {
            Console.WindowHeight = (int)(0.8 * Console.LargestWindowHeight);

            WriteLine(ConsoleColor.White, "X - Exit | P - Run/Pause | S - Step (hold for Slow) | B - Burst");
            WriteLine("Press P, S or B to make something happen.", reportInterval);

            Guid guid;
            byte[] bytes;

            var cursorPos = new CursorLocation();

            while (!exit)
            {
                if (Console.KeyAvailable)
                {
                    ProcessKey(Console.ReadKey(true));
                }

                if (running || burst > 0)
                {
                    guid = Guid.NewGuid();
                    bytes = guid.ToByteArray();
                    ++guidCount;

                    for (int i = 0; i < 16; i++)
                    {
                        var b = bytes[i];
                        ++counts[b];
                    }

                    if (burst > 0) --burst;

                    if (burst == 0 && DateTime.Now > nextReport)
                    {
                        cursorPos.MoveCursor();
                        ReportFrequencies();
                    }
                }
                else
                    Thread.Sleep(20);
            }
        }


        static void ProcessKey(ConsoleKeyInfo keyInfo)
        {
            switch (keyInfo.Key)
            {
                case ConsoleKey.P:
                    running = !running;
                    break;

                case ConsoleKey.B:
                    burst = 100;
                    break;

                case ConsoleKey.S:
                    burst = 1;
                    break;

                case ConsoleKey.X:
                    exit = true;
                    break;
            }
        }


        static void ReportFrequencies()
        {
            Write("\r\n{0} GUIDs generated. Frequencies (%):\r\n\r\n", guidCount);

            const int itemWidth = 11;
            const int colCount = 8; // Console.WindowWidth / (itemWidth + 2);

            for (int i = 0; i < 256; i++)
            {
                var f = (double)counts[i] / (16 * guidCount);
                var c = GetFrequencyColor(f);
                Write(c, RightAdjust(3, "{0:x}", i));
                Write(c, " {0:0.00}".PadRight(itemWidth), f*100);
                if ((i + 1) % colCount == 0) Write("\r\n");
            }

            nextReport = DateTime.Now + reportInterval;
        }


        static ConsoleColor GetFrequencyColor(double f)
        {
            if (f < 0.003) return ConsoleColor.DarkRed;
            if (f < 0.004) return ConsoleColor.Green;
            if (f < 0.005) return ConsoleColor.Yellow;
            return ConsoleColor.White;
        }


        static string RightAdjust(int w, string s, params object[] args)
        {
            if (args.Length > 0)
                s = string.Format(s, args);
            return s.PadLeft(w);
        }

        #region From my library, so I need not include that here...
        class CursorLocation
        {
            public int X, Y;
            public CursorLocation()
            {
                X = Console.CursorLeft;
                Y = Console.CursorTop;
            }

            public void MoveCursor()
            {
                Console.CursorLeft = X;
                Console.CursorTop = Y;
            }
        }


        static public void Write(string s, params object[] args)
        {
            if (args.Length > 0) s = string.Format(s, args);
            Console.Write(s);
        }


        static public void Write(ConsoleColor c, string s, params object[] args)
        {
            var old = Console.ForegroundColor;
            Console.ForegroundColor = c;
            Write(s, args);
            Console.ForegroundColor = old;
        }


        static public void WriteNewline(int count = 1)
        {
            while (count-- > 0) Console.WriteLine();
        }


        static public void WriteLine(string s, params object[] args)
        {
            Write(s, args);
            Console.Write(Environment.NewLine);
        }


        static public void WriteLine(ConsoleColor c, string s, params object[] args)
        {
            Write(c, s, args);
            Console.Write(Environment.NewLine);
        }
        #endregion
    }
}

发布你的结果,女士们,先生们。 :)