Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net Console.WriteLine是否阻塞?_.net_Multithreading_Console - Fatal编程技术网

.net Console.WriteLine是否阻塞?

.net Console.WriteLine是否阻塞?,.net,multithreading,console,.net,Multithreading,Console,Console.WriteLine是否会一直阻塞直到输出被写入,还是会立即返回 如果它阻止,是否有将异步输出写入控制台的方法?是,它阻止。据我所知,框架中没有内置异步控制台写入 在我的办公桌上快速测试一下,会发现是的,它会阻塞 要异步写入控制台,您只需将写入内容发送到另一个线程,然后由该线程将其写入即可。您可以通过让另一个线程旋转来写入消息队列,或者通过链接Task实例来实现这一点,以便对写入进行排序 我之前提出的使用线程池的建议是不好的,因为它不能保证排序,因此,控制台输出可能会混淆。是的,c

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


如果它阻止,是否有将异步输出写入控制台的方法?

是,它阻止。据我所知,框架中没有内置异步控制台写入

在我的办公桌上快速测试一下,会发现是的,它会阻塞

要异步写入控制台,您只需将写入内容发送到另一个线程,然后由该线程将其写入即可。您可以通过让另一个线程旋转来写入消息队列,或者通过链接
Task
实例来实现这一点,以便对写入进行排序


我之前提出的使用线程池的建议是不好的,因为它不能保证排序,因此,控制台输出可能会混淆。

是的,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个Write&WriteLine重载之一)

实现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);
    }
}
请注意,我已经切换到使用任务来管理Begin/End方法:这是因为如果已经有异步写入,BeginWrite方法本身似乎会阻塞

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

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

        AsyncStreamWriter.InjectAsConsoleOut();

        Console.WriteLine(text);

        Console.ReadLine();
    }
}

是,它将阻塞,直到输出写入屏幕。我不确定文档中是否明确说明了这一点,但您可以通过深入查看reflector中的
控制台
类来验证这一点。特别是
initializestDoutror()
方法。为输出流创建
TextWriter
时,它将
AutoFlush
设置为
true

Hmya,控制台输出速度不是特别快。但这是一个永远不需要解决的“问题”。关注奖品:你是为了人类的利益而向控制台写信。而那个人不可能读得那么快

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

Console.WriteLine是否会阻塞,直到 输出已写入或正在写入 马上回来

如果它真的阻塞了,有没有一种方法 将异步输出写入 控制台

如果您使用的是.NET4.0,那么在不阻塞的情况下写入控制台的解决方案非常简单。其思想是将文本值排队,并让单个专用线程执行
控制台.WriteLine
调用。生产者-消费者模式在这里非常理想,因为它保留了使用本机
控制台
类时隐含的时间顺序。NET4.0之所以让这变得容易,是因为它有一个类,可以方便地生成生产者-消费者模式。如果您没有使用.NET4.0,则可以通过下载框架获得一个后端口

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);
  }
}
公共静态类非阻塞控制台
{
私有静态BlockingCollection m_队列=新建BlockingCollection();
静态非阻塞控制台()
{
var线程=新线程(
() =>
{
while(true)Console.WriteLine(m_Queue.Take());
});
thread.IsBackground=true;
thread.Start();
}
公共静态void WriteLine(字符串值)
{
m_队列。添加(值);
}
}

Console.WriteLine
同步运行,
Console.Out
流将在方法返回之前写入。但是,对于大多数生产使用,您应该使用日志框架,而不是标准输出。Microsoft的日志接口显式不包含异步方法,因为

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

Console.Out.WriteAsync(“…”)


Console.Out.WriteLineAsync(“…”)

这是可行的,但是在线程池中启动工作对于控制台编写来说顺序语义很差。即使我从同一个线程启动workitem A和workitem B,也无法保证哪一个将首先运行。我喜欢您的建议,因为它避免了为字符串字节创建中间缓冲区。您可以通过使用线程池线程而不是创建新线程来进一步改进这一点。创建和销毁线程的成本很高。使用线程池线程可以避免这种情况@Aniket:这不会很好,因为控制台会被无序更新。保证写操作以相同的顺序进行的最好方法是使用一个单独的线程。资源消耗可以忽略不计,因为1)只创建了一个线程,2)它将永远存在。这一点很好,但不是每次都会创建一个新线程吗?var thread=new thread(blah…)告诉我,每次进入非阻塞控制台时都会创建一个新线程,对吗?@Aniket:Nah…这是一个静态构造函数,所以每个应用程序域只运行一次。你的建议值得注意,但在我的情况下是适用的
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);
  }
}