Writing to char console on char, the fastest way

In the current project of my work, I have to parse the string and write its parts to the console. Checking how to do this without extra costs, I found that one of the methods I tested was actually faster than Console.WriteLine, which confuses me a bit.

I know that this is not the right way to test, but I usually have a good understanding of the rough β€œit's faster than that”, which I can say after several times.

static void Main(string[] args) { var timer = new Stopwatch(); timer.Restart(); Test1("just a little test string."); timer.Stop(); Console.WriteLine(timer.Elapsed); timer.Restart(); Test2("just a little test string."); timer.Stop(); Console.WriteLine(timer.Elapsed); timer.Restart(); Test3("just a little test string."); timer.Stop(); Console.WriteLine(timer.Elapsed); } static void Test1(string str) { Console.WriteLine(str); } static void Test2(string str) { foreach (var c in str) Console.Write(c); Console.Write('\n'); } static void Test3(string str) { using (var stream = new StreamWriter(Console.OpenStandardOutput())) { foreach (var c in str) stream.Write(c); stream.Write('\n'); } } 

As you can see, Test1 uses Console.WriteLine. My first thought was to just call Write for each char, see Test2. But this led to getting about twice as long. My guess would be that it erases after each recording, which makes it slower. So I tried Test3 using StreamWriter (AutoFlush off), which led to 25% faster than Test1, and I'm really curious what it is. Or maybe recording to the console cannot be verified correctly? (noticed some strange data when adding additional test cases ...)

Can someone enlighten me?

Also, if there is a better way to do this (going through a line and only writing parts of it to the console), feel free to comment on it.

+7
source share
4 answers

At first I agree with the other comments that your test harness is poor ... I rewrote it and included it below. The result after overwriting will be a clear winner:

 //Test 1 = 00:00:03.7066514 //Test 2 = 00:00:24.6765818 //Test 3 = 00:00:00.8609692 

From this, you are sure that a buffered stream writer is better than 25% faster. This is faster just because it is buffered. Internally, StreamWriter uses a default buffer size of about 1 ~ 4kb (depending on the type of stream). If you design StreamWriter with an 8-byte buffer (the minimum allowed), you will see that most of your performance improvements disappear. You can also see this using the Flush () call after each entry.

Here is a test rewritten to get the numbers above:

  private static StreamWriter stdout = new StreamWriter(Console.OpenStandardOutput()); static void Main(string[] args) { Action<string>[] tests = new Action<string>[] { Test1, Test2, Test3 }; TimeSpan[] timming = new TimeSpan[tests.Length]; // Repeat the entire sequence of tests many times to accumulate the result for (int i = 0; i < 100; i++) { for( int itest =0; itest < tests.Length; itest++) { string text = String.Format("just a little test string, test = {0}, iteration = {1}", itest, i); Action<string> thisTest = tests[itest]; //Clear the console so that each test begins from the same state Console.Clear(); var timer = Stopwatch.StartNew(); //Repeat the test many times, if this was not using the console //I would use a much higher number, say 10,000 for (int j = 0; j < 100; j++) thisTest(text); timer.Stop(); //Accumulate the result, but ignore the first run if (i != 0) timming[itest] += timer.Elapsed; //Depending on what you are benchmarking you may need to force GC here } } //Now print the results we have collected Console.Clear(); for (int itest = 0; itest < tests.Length; itest++) Console.WriteLine("Test {0} = {1}", itest + 1, timming[itest]); Console.ReadLine(); } static void Test1(string str) { Console.WriteLine(str); } static void Test2(string str) { foreach (var c in str) Console.Write(c); Console.Write('\n'); } static void Test3(string str) { foreach (var c in str) stdout.Write(c); stdout.Write('\n'); } 
+5
source

I tested your test 10,000 times, and the results on my computer are as follows:

 test1 - 0.6164241 test2 - 8.8143273 test3 - 0.9537039 

this is the script i used:

  static void Main(string[] args) { Test1("just a little test string."); // warm up GC.Collect(); // compact Heap GC.WaitForPendingFinalizers(); // and wait for the finalizer queue to empty Stopwatch timer = new Stopwatch(); timer.Start(); for (int i = 0; i < 10000; i++) { Test1("just a little test string."); } timer.Stop(); Console.WriteLine(timer.Elapsed); } 
+3
source

I changed the code to run each test 1000 times.

  static void Main(string[] args) { var timer = new Stopwatch(); timer.Restart(); for (int i = 0; i < 1000; i++) Test1("just a little test string."); timer.Stop(); TimeSpan elapsed1 = timer.Elapsed; timer.Restart(); for (int i = 0; i < 1000; i++) Test2("just a little test string."); timer.Stop(); TimeSpan elapsed2 = timer.Elapsed; timer.Restart(); for (int i = 0; i < 1000; i++) Test3("just a little test string."); timer.Stop(); TimeSpan elapsed3 = timer.Elapsed; Console.WriteLine(elapsed1); Console.WriteLine(elapsed2); Console.WriteLine(elapsed3); Console.Read(); } 

My conclusion:

 00:00:05.2172738 00:00:09.3893525 00:00:05.9624869 
+2
source

I also ran this 10,000 times and got the following results:

 00:00:00.6947374 00:00:09.6185047 00:00:00.8006468 

This is similar to what others have observed. I was curious why Test3 was slower than Test1 , so I wrote the fourth test:

 timer.Start(); using (var stream = new StreamWriter(Console.OpenStandardOutput())) { for (int i = 0; i < testSize; i++) { Test4("just a little test string.", stream); } } timer.Stop(); 

This repeats the flow for each test, thereby avoiding the overhead of recreating it each time. Result:

 00:00:00.4090399 

Although this is the fastest, it writes all the output at the end of the using block, which might not be what you need. I would suggest that this approach would also chew more memory.

+2
source

All Articles