首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Console.WriteLine会阻塞吗?

Console.WriteLine会阻塞吗?
EN

Stack Overflow用户
提问于 2010-09-09 00:51:44
回答 8查看 22.4K关注 0票数 47

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

如果它阻塞了,是否有一种方法可以将异步输出写入控制台?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2010-09-09 02:03:12

会阻塞Console.WriteLine直到输出被写入,还是立即返回?

是。

如果阻塞,有没有一种方法可以将异步输出写到控制台?

如果您使用的是.NET 4.0,那么在不阻塞的情况下写入控制台的解决方案是非常简单的。其思想是对文本值进行排队,并让单个专用线程执行Console.WriteLine调用。生产者-消费者模式在这里非常理想,因为它保留了使用本机Console类时隐含的时态排序。.NET 4.0之所以能让这一切变得简单,是因为它有BlockingCollection类,这个类可以促进生产者-消费者模式的产生。如果你使用的不是.NET 4.0,那么你可以通过下载Reactive Extensions框架获得一个后端口。

代码语言:javascript
复制
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);
  }
}
票数 47
EN

Stack Overflow用户

发布于 2014-09-17 23:54:50

Console.WriteLine同步运行,并在方法返回之前写入Console.Out流。但是,对于大多数生产用途,您应该使用日志记录框架,而不是标准输出。微软的日志接口显式地不包含异步方法,因为"Logging should be so fast that it isn't worth the performance cost of asynchronous code."

如果您的用例仍然需要写入标准输出,并且使用异步/等待的性能成本值得权衡,那么从.NET 4.5开始,TextWriter支持WriteAsyncWriteLineAsync方法,因此您现在可以使用:

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

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

票数 45
EN

Stack Overflow用户

发布于 2010-09-09 01:01:01

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

编辑-一些示例代码,帮助您入门:

代码语言:javascript
复制
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个Write & WriteLine重载中的一个)

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

代码语言:javascript
复制
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

或者,编写一个异步TextWriter,使用Console.SetOut注入它,然后完全像往常一样调用Console.WriteLine。

TextWriter应该是这样的:

代码语言:javascript
复制
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;
        }
    }
}

请注意,我已经切换到使用Tasks来管理Begin/End方法:这是因为如果已经有异步写入正在进行,则BeginWrite方法本身似乎会阻塞。

一旦你有了这个类,只需调用注入方法,你对Console.WriteLine的每个调用,无论你在哪里或使用哪个重载,都会变成异步的。Comme ca:

代码语言:javascript
复制
class Program
{
    static void Main(string[] args)
    {
        string text = "Hello World!";

        AsyncStreamWriter.InjectAsConsoleOut();

        Console.WriteLine(text);

        Console.ReadLine();
    }
}
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3670057

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档