2012-03-08 60 views
-5

編輯:得到五個downvotes但沒有評論說任何關於爲什麼,我試圖重新構造這個問題。我只能假設選票是因爲人們看到很多文字,也許認爲這裏甚至沒有問題。控制檯應用程序中的奇怪問題

我寫的代碼(錯誤)表現得很奇怪。看起來代碼在其他計算機上的運行方式不同,所以如果不能重現問題,請不要生氣。

我有一個看,只是爲了好玩,在GUID中出現不同字節的頻率。我注意到,guid的字符串表示總是包含「4」。我沒有在維基百科上讀過它,而是試着去思考它可能是什麼,因爲做一點「原創性研究」並偶爾做一下自己的想法可能很有趣。 (然後再閱讀wiki!)

當我嘗試使用「突發」功能時,我的機器出現了一個奇怪的問題。如果它可以在您的環境中重現,您可以通過運行應用程序並打B來重新創建它。這應該會導致100步驟的突發(即創建100個新的guid,僅在突然,因爲寫入控制檯是非常慢)。但它實際上只有一步!

我在分配突發變量的ProcessKey()中設置了一個斷點。當我退出該方法時,我注意到在調試輸出中線程退出。這不是巧合;它每次都可靠地發生。然後,我的手錶向我顯示剛剛在上一步中分配給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 
    } 
} 
+5

我已經運行的應用程序,並跨過(F10)的ProcessKey方法和連拍的設置是否正確。我也走了(F11),然後走出去(Shift + F11),我看到兩種情況下突發= 100。不知道你在做什麼。我應該補充一點,Guids包含了你的機器的各個方面,所以我不會期望一個統一的分佈,否則你將有機會在系統之間進行Guid碰撞。畢竟,它應該是一個全球唯一的標識符。 – Lazarus 2012-03-08 16:53:06

+1

這些線程退出可能與調試器的活動而不是您的代碼有關嗎? – dsolimano 2012-03-08 17:07:33

+0

謝謝。我希望有人投票會留下評論,讓我知道爲什麼。我知道**的第一句話(短而甜的「嘗試這個」)不是一個問題,並且可能使它看起來毫無疑問。但是,如果人們真正閱讀,他們會看到它有一點背景,一個具體的問題,以及許多重現結果的代碼。 – 2012-03-08 20:43:15

回答

1

Ehem。我試着在我的HTPC上運行代碼,與我編寫的計算機不同,但現在我無法重現該問題。也就是說,我確實觀察到突發導致了一個步驟,但這是由於我的代碼中存在邏輯錯誤(當達到報告間隔時它將突發設置爲-1)。很難相信我做了而不是設置了我的斷點,走過了一步,看到變量被破壞了,因爲我知道這會是多麼奇怪,並且嘗試了好幾次以確保我看到了我認爲我看到的東西。但是也很難相信我曾經在框架/ clr中遇到過這樣一個奇怪而深刻的bug,特別是考慮到我的代碼有一個錯誤,導致我首先附加了調試器的東西..

無論如何,我會將其標記爲已關閉。如果有人想玩這個修改過的代碼,請在這裏發佈。我修正了錯誤,使輸出更緊湊一些,所以它在不太寬鬆的屏幕上比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的每一個由所有字節的0.34%,在這種特殊情況下產生的(509194所有的GUID,但我得到這個結果每時間超過10萬次左右)。有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 
    } 
} 

發佈您的結果,女士們先生們。 :)

+0

如果我記得,我會盡快接受這個答案。同時,請不要恨我,因爲stackoverflow不會讓我標記自己的答案,甚至對我自己的問題。 (無論如何,我認爲他們的「信用」制度無視回答自己的問題。不知道爲什麼這個政策是適當的。) – 2012-03-08 23:01:27