¿Console.WriteLine bloquea?

¿ Console.WriteLine bloquea hasta que la salida se haya escrito o se devuelva inmediatamente?

Si se bloquea, ¿hay algún método para escribir una salida asíncrona en la consola?

¿Console.WriteLine bloquea hasta que la salida se haya escrito o se devuelva inmediatamente?

Sí.

Si se bloquea, ¿hay algún método para escribir una salida asíncrona en la consola?

La solución para escribir en la consola sin bloquear es sorprendentemente trivial si está usando .NET 4.0. La idea es poner en cola los valores de texto y dejar que un solo hilo dedicado haga las llamadas Console.WriteLine . El patrón productor-consumidor es ideal aquí porque preserva el orden temporal que está implícito cuando se usa la clase de Console nativa. La razón por la cual .NET 4.0 lo hace fácil es porque tiene la clase BlockingCollection que facilita la producción de un patrón productor-consumidor. Si no está utilizando .NET 4.0, entonces puede obtener un respaldo mediante la descarga del marco de Extensiones reactivas .

 public static class NonBlockingConsole { private static BlockingCollection m_Queue = new BlockingCollection(); 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); } } 

A partir de .NET 4.5, TextWriter admite los métodos WriteAsync y WriteLineAsync , por lo que ahora puede usar:

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

y

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

Sí, Console.WriteLine se bloqueará hasta que se escriba la salida, ya que llama al método Write de la instancia de flujo subyacente. Puede escribir de forma asíncrona a la transmisión de salida estándar (que se conoce como transmisión subyacente) llamando a Console.OpenStandardOutput para obtener la transmisión, luego llamando a BeginWrite y EndWrite en esa transmisión; tenga en cuenta que tendrá que hacer su propia encoding de cadena (convirtiendo el objeto System.String en un byte []) ya que las secuencias solo aceptan matrices de bytes.

Editar – Algunos ejemplos de código para comenzar:

 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 – Una versión alternativa, basada en la sugerencia de Brian Gideon en los comentarios (tenga en cuenta que esto solo cubre una de las dieciséis sobrecargas de Write & WriteLine que están disponibles)

Implemente los métodos Begin / End como extensiones de la clase TextWriter, luego agregue una clase AsyncConsole para llamarlos:

 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(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(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); } } 

Editar 3

Alternativamente, escriba un TextWriter asincrónico, inyéctelo usando Console.SetOut y luego llame a Console.WriteLine exactamente como lo hace normalmente.

El TextWriter sería algo así como:

 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; } } } 

Tenga en cuenta que he cambiado al uso de tareas para administrar los métodos Begin / End: esto se debe a que el método BeginWrite parece bloquearse si ya hay una escritura asíncrona en progreso.

Una vez que tenga esa clase, simplemente llame al método de inyección y cada llamada que haga a Console.WriteLine, independientemente de dónde la realice o con qué sobrecarga, se volverá asíncrona. Comme ca:

 class Program { static void Main(string[] args) { string text = "Hello World!"; AsyncStreamWriter.InjectAsConsoleOut(); Console.WriteLine(text); Console.ReadLine(); } } 

Hmya, la salida de la consola no es particularmente rápida. Pero este es un ‘problema’ que nunca necesita ser arreglado. Mantenga sus ojos en el premio: está escribiendo en la consola para el beneficio de un humano. Y esa persona no está cerca para poder leer tan rápido.

Si la salida se redirige, deja de ser lenta. Si eso todavía tiene un impacto en su progtwig, tal vez esté escribiendo demasiada información. Escribir en un archivo en su lugar.

Sí, se bloqueará hasta que la salida se escriba en la pantalla. No estoy seguro de que esto se indique explícitamente en la documentación, pero puede verificarlo al profundizar en la clase de la Console en el reflector. En particular, el método InitializeStdOutError() . Al crear el TextWriter para la secuencia de salida, establece AutoFlush en true

Una prueba rápida en mi escritorio sugeriría que sí, bloquea.

Para escribir de forma asíncrona en la consola, simplemente podría enviar sus escrituras a otro hilo que luego podría escribirlas. Usted puede hacer eso teniendo otro hilo girando que tiene una cola de mensajes para escribir, o encadenando instancias de Task para que sus escrituras sean ordenadas.

Mi sugerencia anterior de utilizar el grupo de subprocesos es mala, ya que no garantiza la ordenación y, por lo tanto, la salida de la consola podría mezclarse.

Sí bloquea. Y no hay escrituras de consola asincrónicas integradas en el marco que yo sepa.