Console.WriteLine很慢

我运行了数百万条记录,有时我必须使用Console.WriteLine进行调试才能看到发生了什么。

但是, Console.WriteLine非常慢,比写入文件慢得多。

但它非常方便 – 有没有人知道加速它的方法?

您可以使用OutputDebugString API函数将字符串发送到调试器。 它不会等待重绘任何东西,这可能是你不能过多地挖掘低级别东西所能获得的最快的东西。 您为此函数提供的文本将进入Visual Studio输出窗口。

 [的DllImport( “KERNEL32.DLL”)]
 static extern void OutputDebugString(string lpOutputString);

然后你只需要调用OutputDebugString("Hello world!");

如果它仅用于调试目的,则应使用Debug.WriteLine 。 这很可能比使用Console.WriteLine快一点。

Debug.WriteLine("There was an error processing the data.");

做这样的事情:

 public static class QueuedConsole { private static StringBuilder _sb = new StringBuilder(); private static int _lineCount; public void WriteLine(string message) { _sb.AppendLine(message); ++_lineCount; if (_lineCount >= 10) WriteAll(); } public void WriteAll() { Console.WriteLine(_sb.ToString()); _lineCount = 0; _sb.Clear(); } } QueuedConsole.WriteLine("This message will not be written directly, but with nine other entries to increase performance."); //after your operations, end with write all to get the last lines. QueuedConsole.WriteAll(); 

这是另一个例子: Console.WriteLine是否阻止?

一个旧的线程,可能不是OP正在寻找的,但我最近遇到了同样的问题,实时处理音频数据。

我使用此代码将Console.WriteLineDebug.WriteLine进行了比较,并将DebugView用作dos框替代方案。 它只是一个可执行文件(无需安装),可以非常简洁的方式进行自定义(filter和颜色!)。 它没有成千上万行的问题,并且很好地管理内存(即使经过几天的记录,我也找不到任何泄漏)。

在不同环境中进行一些测试后(例如:虚拟机,IDE,后台进程运行等),我做了以下观察:

  • Debug几乎总是更快
  • 对于小型线阵(<1000),它的速度提高了约10倍
  • 对于较大的块,它似乎收敛到大约3倍
  • 如果Debug输出进入IDE,则Console更快:-)
  • 如果DebugView没有运行, Debug会更快
  • 对于非常大量的连续输出(> 10000), Debug变慢并且Console保持不变。 我认为这是由于内存,Debug必须分配而Console不是。
  • 显然,如果DebugView实际上是“在视图中”,它会有所不同,因为许多gui更新对系统的整体性能有重大影响,而Console只是挂起,如果可见或不可见。 但很难将数字放在那个……

我没有尝试多个线程写入Console ,因为我认为这通常应该避免。 从多个线程写入Debug时,我从未遇到(性能)问题。

如果使用Release设置进行编译,通常会省略所有Debug语句, Trace应该生成与Debug相同的行为。

我使用VS2017.Net 4.6.1

很抱歉这么多代码,但我不得不调整它实际测量我想要的东西。 如果您发现代码有任何问题(偏见等),请发表评论。 我希望能为现实生活系统获得更精确的数据。

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; namespace Console_vs_Debug { class Program { class Trial { public string name; public Action console; public Action debug; public List < float > consoleMeasuredTimes = new List < float > (); public List < float > debugMeasuredTimes = new List < float > (); } static Stopwatch sw = new Stopwatch(); private static int repeatLoop = 1000; private static int iterations = 2; private static int dummy = 0; static void Main(string[] args) { if (args.Length == 2) { repeatLoop = int.Parse(args[0]); iterations = int.Parse(args[1]); } // do some dummy work for (int i = 0; i < 100; i++) { Console.WriteLine("-"); Debug.WriteLine("-"); } for (int i = 0; i < iterations; i++) { foreach(Trial trial in trials) { Thread.Sleep(50); sw.Restart(); for (int r = 0; r < repeatLoop; r++) trial.console(); sw.Stop(); trial.consoleMeasuredTimes.Add(sw.ElapsedMilliseconds); Thread.Sleep(1); sw.Restart(); for (int r = 0; r < repeatLoop; r++) trial.debug(); sw.Stop(); trial.debugMeasuredTimes.Add(sw.ElapsedMilliseconds); } } Console.WriteLine("---\r\n"); foreach(Trial trial in trials) { var consoleAverage = trial.consoleMeasuredTimes.Average(); var debugAverage = trial.debugMeasuredTimes.Average(); Console.WriteLine(trial.name); Console.WriteLine($ " console: {consoleAverage,11:F4}"); Console.WriteLine($ " debug: {debugAverage,11:F4}"); Console.WriteLine($ "{consoleAverage / debugAverage,32:F2} (console/debug)"); Console.WriteLine(); } Console.WriteLine("all measurements are in milliseconds"); Console.WriteLine("anykey"); Console.ReadKey(); } private static List < Trial > trials = new List < Trial > { new Trial { name = "constant", console = delegate { Console.WriteLine("A static and constant string"); }, debug = delegate { Debug.WriteLine("A static and constant string"); } }, new Trial { name = "dynamic", console = delegate { Console.WriteLine("A dynamically built string (number " + dummy++ + ")"); }, debug = delegate { Debug.WriteLine("A dynamically built string (number " + dummy++ + ")"); } }, new Trial { name = "interpolated", console = delegate { Console.WriteLine($ "An interpolated string (number {dummy++,6})"); }, debug = delegate { Debug.WriteLine($ "An interpolated string (number {dummy++,6})"); } } }; } } 

尝试使用System.Diagnostics Debug类? 您可以使用Console.WriteLine完成相同的操作。

您可以在此处查看可用的类方法: http : //msdn.microsoft.com/en-us/library/system.diagnostics.debug.aspx

只是我有时使用的一个小技巧:如果你通过打开另一个窗口从控制台窗口移除焦点,并保持它直到它完成,它将不会重绘窗口,直到你重新聚焦,显着加快它。 只需确保将缓冲区设置得足够高,以便可以向后滚动所有输出。

控制台输出是一个IO流,与所有IO一样,它将比任何内存CPU处理慢。

大多数IO类(如FileStream )现在具有异步等效,因此您可以在不阻塞CPU的情况下写入流,但是从未为此升级过Console 。 它也比文件慢得多,因为它是在屏幕上呈现而不是直接发送到磁盘或网络硬件,这就是为什么你有时可以看到控制台窗口在它变小时加速并且在屏幕。

一个简单的包装器将允许您使用异步方法写入Console流:

 var sw = new StreamWriter(Console.OpenStandardOutput()); await sw.WriteLineAsync("..."); 

您还可以设置较大的缓冲区以使用同步方法,并在刷新时偶尔进行阻塞。

 var sw = new StreamWriter(Console.OpenStandardOutput(), Encoding.UTF8, 8192); sw.Write("...") // this will block for flushing when the buffer size of 8192 is full 

如果你想要最快的写入,你需要创建自己的缓冲类,它将在内存中保持写入并在后台异步地保持刷新到控制台。 .NET Core 2.1中的新Channel使这非常简单快捷。 很多其他问题显示代码,但如果您需要提示,请发表评论。