代码之家  ›  专栏  ›  技术社区  ›  Peter Johansson

console.writeline是否阻止?

  •  36
  • Peter Johansson  · 技术社区  · 15 年前

    Console.WriteLine 在写入输出之前阻塞,还是立即返回?

    如果它确实是block,那么是否有将异步输出写入控制台的方法?

    7 回复  |  直到 10 年前
        1
  •  39
  •   Nolonar    10 年前

    在 输出已写入或已写入 立即返回?

    对。

    如果它确实阻塞,是否有一种方法 将异步输出写入 慰问?

    如果您使用.NET 4.0,那么在不阻塞的情况下写入控制台的解决方案是非常简单的。其思想是将文本值排队,并让一个专用线程执行 Console.WriteLine 电话。生产者-消费者模式在这里是理想的,因为它保留了使用本机时隐式的时间顺序 Console 班级。.NET 4.0之所以如此简单,是因为它具有 BlockingCollection 类,它有助于生成生产者-消费者模式。如果您不使用.NET 4.0,则可以通过下载 Reactive Extensions 框架。

    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);
      }
    }
    
        2
  •  33
  •   Stephen Rudolph    11 年前

    根据.NET 4.5, TextWriter 支持 WriteAsync WriteLineAsync 方法,现在可以使用:

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

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

        3
  •  10
  •   FacticiusVir    15 年前

    是的,console.writeline将阻塞,直到写入输出,因为它调用底层流实例的写入方法。您可以通过调用console.openstandardoutput以获取流,然后在该流上调用BeginWrite和EndWrite,异步写入标准输出流(即底层流);请注意,您必须执行自己的字符串编码(将System.String对象转换为byte[]),因为流只接受字节数组。

    编辑 -一些示例代码用于启动:

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

    编辑2 -另一个版本,基于Brian Gideon在评论中的建议(请注意,这只涵盖了可用的16个写行过载中的一个)

    将begin/end方法实现为TextWriter类的扩展,然后添加一个AsyncConsole类来调用它们:

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

    编辑3

    或者,编写异步文本编写器,使用console.setout注入它,然后调用console.writeline 确切地 正常情况下。

    文本编写器类似于:

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

    请注意,我已经切换到使用任务来管理开始/结束方法:这是因为如果已经在进行异步写入,那么BeginWrite方法本身似乎会阻塞。

    一旦你有了这个类,只需调用注入方法和 每一个 调用console.writeline,无论在何处进行或使用何种重载,都将成为异步的。共同CA:

    class Program
    {
        static void Main(string[] args)
        {
            string text = "Hello World!";
    
            AsyncStreamWriter.InjectAsConsoleOut();
    
            Console.WriteLine(text);
    
            Console.ReadLine();
        }
    }
    
        4
  •  6
  •   Hans Passant    15 年前

    嗯,控制台输出不是特别快。但这是一个不需要解决的“问题”。注意奖品:你是为了人类的利益而写信给主控台的。那个人不太可能读得那么快。

    如果输出被重定向,它将停止变慢。如果这仍然对你的计划有影响,那么你可能只是在写 方式 信息太多。改为写入文件。

        5
  •  1
  •   Jeff Yates    15 年前

    我桌上的一个快速测试表明是的,它会阻塞。

    要异步地写入控制台,您可以将您的写操作发送到另一个线程,然后再将它们写出。您可以通过让另一个线程旋转并编写一个消息队列,或者通过链接来实现这一点。 Task 使您的写操作有序的实例。

    我之前关于使用线程池的建议是一个糟糕的建议,因为它不能保证排序,因此,您的控制台输出可能会混淆。

        6
  •  0
  •   JaredPar    15 年前

    是的,它将一直阻塞,直到输出写入屏幕。我不确定文档中是否明确说明了这一点,但您可以通过挖掘 Console 反射层中的类。尤其是 InitializeStdOutError() 方法。当创建 TextWriter 对于它设置的输出流 AutoFlush true

        7
  •  -1
  •   Matthew Whited    15 年前

    是的,它阻塞了。而且我所知道的框架中没有内置异步控制台写入。

    推荐文章