我浏览了数百万条记录,有时我必须使用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();
这是另一个例子:Does Console.WriteLine block?
一个旧的线程,可能不是OP正在寻找的,但我最近遇到了同样的问题,实时处理音频数据。
我将Console.WriteLine
与Debug.WriteLine
与this code进行了比较,并使用DebugView作为dos box替代品。它只是一个可执行文件(无需安装),可以非常简洁的方式进行自定义(过滤器和颜色!)。它没有成千上万行的问题,并且很好地管理内存(即使经过几天的记录,我也找不到任何泄漏)。
在不同环境中进行一些测试后(例如:虚拟机,IDE,后台进程运行等),我做了以下观察:
Debug
几乎总是更快Debug
输出进入IDE,Console
更快:-)Debug
会变得更快Debug
变慢并且Console
保持不变。我认为这是由于内存,Debug必须分配和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
为什么控制台很慢:
FileStream
)都有异步方法,但Console
类从未更新过,它总是阻塞线程。Console.WriteLine
由SyncTextWriter
支持,它使用全局锁来防止多个线程写入部分行。这是一个主要的瓶颈,使所有线程等待单个阻塞写入调用按顺序发生。解决方案:
使用包装StreamWriter,然后使用异步方法写入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
如果你想要最快的写入,你需要创建自己的缓冲类,写入内存并使用单个线程在后台异步刷新到控制台而不锁定。 new Channel<T>
class in .NET Core 2.1使这简单快速。许多其他问题显示代码,但如果您需要提示,请发表评论。
我有时会使用一个小技巧:如果你通过打开另一个窗口从控制台窗口中移除焦点,并将其保留直到完成,它将不会重新绘制窗口,直到你重新聚焦,显着加快速度。只需确保缓冲区设置得足够高,以便可以向后滚动所有输出。