为什么Console.WriteLine(...)太慢了?任何替代品?

时间:2017-03-08 12:01:21

标签: c#

似乎Console.WriteLine(...)在C#中确实很慢。

这是我测试过的代码。

var iterations = 5000;
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < iterations; i++) 
    Console.WriteLine("adsdsaddhfuihdsuifhdsufudshfoadfdshoadsuoadsuioadsihfuidh");
watch.Stop();
double msPerOp = 1.0 * watch.ElapsedMilliseconds / iterations;
Console.WriteLine("{0} ms/op", msPerOp);

在我的笔记本电脑中,它会打印5.731 ms/op

为什么这么慢?

据我所知,用其他语言打印到控制台并不是那么慢。 例如,在Go中,具有相同字符串的fmt.Println(...)仅在我的笔记本电脑中占用416275 ns/op (= 0.416275 ms/op)

(使用go test -bench .测试)

为什么Console.WriteLine(...)在c#中这么慢?有没有我可以使用的替代方案,其性能与Go fmt.Println(...)相似?

EDIT) 我需要快速Console.WriteLine(...)的原因如下。

我的应用程序通过Windows消息循环不断收到大量实时数据(20~80数据/秒),我希望每次收到Console.WriteLine时都打印数据。我应该快速打印它,因为如果没有,实时数据会被延迟。

然而,似乎Console.WriteLine(...)需要5~10ms(对于长字符串)..这对于实时数据处理来说太慢了。

1 个答案:

答案 0 :(得分:3)

我不知道您的笔记本电脑是否真的慢得多,但对我来说(发布版本,在Windows 7 x64工作站上运行),您的测试代码输出为0.056 ms / op。

我尝试将WinAPI WriteConsole函数作为比较,但它根本没有提高性能(0.0586 ms / op)。

您可以自己比较,是否得到不同的结果。

public class Program
{
    public enum StandardHandleType
    {
        STD_INPUT_HANDLE = -10,
        STD_OUTPUT_HANDLE = -11,
        STD_ERROR_HANDLE = -12
    }

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    public static extern IntPtr GetStdHandle(StandardHandleType handleType);

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    public static extern bool WriteConsole(
        IntPtr hConsoleOutput,
        string lpBuffer,
        int nNumberOfCharsToWrite,
        ref int lpNumberOfCharsWritten,
        IntPtr lpReserved
        );

    static void Main()
    {
        IntPtr console = GetStdHandle(StandardHandleType.STD_OUTPUT_HANDLE);

        int written = 0;

        var iterations = 5000;
        var watch = new Stopwatch();
        watch.Start();
        string s = "adsdsaddhfuihdsuifhdsufudshfoadfdshoadsuoadsuioadsihfuidh\n";
        for (int i = 0; i < iterations; i++)
            //Console.WriteLine("adsdsaddhfuihdsuifhdsufudshfoadfdshoadsuoadsuioadsihfuidh");
            WriteConsole(console, s, s.Length, ref written, IntPtr.Zero);
        watch.Stop();
        double msPerOp = 1.0 * watch.ElapsedMilliseconds / iterations;
        Console.WriteLine("{0} ms/op", msPerOp);
        Console.ReadKey();
    }
}