Does Console.WriteLine block?

Does Console.WriteLine block until the output has been written or does it return immediately?

If it does block is there a method of writing asynchronous output to the Console?


Does Console.WriteLine block until the output has been written or does it return immediately?

Yes.

If it does block is there a method of writing asynchronous output to the Console?

The solution to writing to the console without blocking is surprisingly trivial if you are using .NET 4.0. The idea is to queue up the text values and let a single dedicated thread do the Console.WriteLine calls. The producer-consumer pattern is ideal here because it preserves the temporal ordering that is implicit when using the native Console class. The reason why .NET 4.0 makes this easy is because it has the BlockingCollection class which facilitates the production of a producer-consumer pattern. If you are not using .NET 4.0 then you can get a backport by downloading the Reactive Extensions framework.

public static class NonBlockingConsole
{
  private static BlockingCollection<string> m_Queue = new BlockingCollection<string>();

  static NonBlockingConsole()
  {
    var thread = new Thread(
      () =>
      {
        while (true) Console.WriteLine(m_Queue.Take());
      });
    thread.IsBackground = true;
    thread.Start();
  }

  public static void WriteLine(string value)
  {
    m_Queue.Add(value);
  }
}

Console.WriteLine runs synchronously and the Console.Out stream will be written to before the method returns. However, for most production usage, you should be using a logging framework instead of standard out. Microsoft's logging interface explicitly does not contain asynchronous method because "Logging should be so fast that it isn't worth the performance cost of asynchronous code.".

If your use case still calls for writing to standard out and the performance cost of using async/await is worth the tradeoff then as of .NET 4.5, TextWriter supports the WriteAsync and WriteLineAsync methods, so you can now use:

Console.Out.WriteAsync("...");

and

Console.Out.WriteLineAsync("...");


Yes, Console.WriteLine will block until the output is written, as it calls the Write method of the underlying stream instance. You can write asynchronously to the Standard Out stream (which is said underlying stream) by calling Console.OpenStandardOutput to get the stream, then calling BeginWrite and EndWrite on that stream; note that you'll have to do your own string encoding (converting the System.String object to a byte[]) as streams only accept byte arrays.

Edit - Some example code to get you started:

using System;
using System.IO;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        string text = "Hello World!";

        Stream stdOut = Console.OpenStandardOutput();

        byte[] textAsBytes = Encoding.UTF8.GetBytes(text);

        IAsyncResult result = stdOut.BeginWrite(textAsBytes, 0, textAsBytes.Length, callbackResult => stdOut.EndWrite(callbackResult), null);

        Console.ReadLine();
    }
}

Edit 2 - An alternate version, based on Brian Gideon's suggestion in the comments (note that this only covers one of the sixteen overloads of Write & WriteLine that are available)

Implement Begin/End methods as extensions of the TextWriter class, then add an AsyncConsole class to call them:

using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        string text = "Hello World!";

        AsyncConsole.WriteLine(text);

        Console.ReadLine();
    }
}

public static class TextWriterExtensions
{
    public static IAsyncResult BeginWrite(this TextWriter writer, string value, AsyncCallback callback, object state)
    {
        return Task.Factory.StartNew(x => writer.Write(value), state).ContinueWith(new Action<Task>(callback));
    }

    public static void EndWrite(this TextWriter writer, IAsyncResult result)
    {
        var task = result as Task;

        task.Wait();
    }

    public static IAsyncResult BeginWriteLine(this TextWriter writer, string value, AsyncCallback callback, object state)
    {
        return Task.Factory.StartNew(x => writer.WriteLine(value), state).ContinueWith(new Action<Task>(callback));
    }

    public static void EndWriteLine(this TextWriter writer, IAsyncResult result)
    {
        var task = result as Task;

        task.Wait();
    }
}

public static class AsyncConsole
{
    public static IAsyncResult Write(string value)
    {
        return Console.Out.BeginWrite(value, callbackResult => Console.Out.EndWrite(callbackResult), null);
    }

    public static IAsyncResult WriteLine(string value)
    {
        return Console.Out.BeginWriteLine(value, callbackResult => Console.Out.EndWriteLine(callbackResult), null);
    }
}

Edit 3

Alternately, write an asynchronous TextWriter, inject it using Console.SetOut and then call Console.WriteLine exactly as normal.

The TextWriter would be something like:

using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

public class AsyncStreamWriter
    : TextWriter
{
    private Stream stream;
    private Encoding encoding;

    public AsyncStreamWriter(Stream stream, Encoding encoding)
    {
        this.stream = stream;
        this.encoding = encoding;
    }

    public override void Write(char[] value, int index, int count)
    {
        byte[] textAsBytes = this.Encoding.GetBytes(value, index, count);

        Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, textAsBytes, 0, textAsBytes.Length, null);
    }

    public override void Write(char value)
    {
        this.Write(new[] { value });
    }

    public static void InjectAsConsoleOut()
    {
        Console.SetOut(new AsyncStreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding));
    }

    public override Encoding Encoding
    {
        get
        {
            return this.encoding;
        }
    }
}

Note that I've switched to using Tasks to manage the Begin/End methods: this is because the BeginWrite method itself seems to block if there's already an async write in progress.

Once you have that class, just call the injection method and every call you make to Console.WriteLine, regardless of where you make it or with which overload, will become asynchronous. Comme ca:

class Program
{
    static void Main(string[] args)
    {
        string text = "Hello World!";

        AsyncStreamWriter.InjectAsConsoleOut();

        Console.WriteLine(text);

        Console.ReadLine();
    }
}