And*_*sen 6 c# asynchronous console-application
要重定向标准输入、标准输出或标准错误流,请分别调用 Console.SetIn、Console.SetOut 或 Console.SetError 方法。使用这些流的 I/O 操作是同步的,这意味着多个线程可以读取或写入流。这意味着如果对象表示控制台流,则通常异步的方法(例如 TextReader.ReadLineAsync)将同步执行。
这是否意味着即使输出被重定向到一个文件,这段代码也会以同步方式执行?
Console.Out.WriteLineAsync("Hello World Async");
真实世界的场景是:如果我的程序将日志输出到标准输出,并且以将输出重定向到文件或通过管道传输到另一个程序的方式调用它,如果缓冲区没有被及时消耗,我的程序是否会停止操作系统或管道接收者?
或者,任何人都可以想出一种我可以确定两种方式的方法吗?
如果我的程序将日志输出到 stdout,并且以将输出重定向到文件或通过管道传输到另一个程序的方式调用它,那么如果操作系统或管道接收者没有及时消耗缓冲区,我的程序是否会停止运行?
是的,它会。
当您调用 时Console.SetOut(),此代码将执行:
public static void SetOut(TextWriter newOut) {
if (newOut == null)
throw new ArgumentNullException("newOut");
Contract.EndContractBlock();
#pragma warning disable 618
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
#pragma warning restore 618
#if FEATURE_CODEPAGES_FILE // if no codepages file then we are locked into default codepage and this field is not used
_isOutTextWriterRedirected = true;
#endif
newOut = TextWriter.Synchronized(newOut);
lock(InternalSyncObject) {
_out = newOut;
}
}
Run Code Online (Sandbox Code Playgroud)
即,新的输出始终TextWriter是由 . 返回的 writer 。反过来总是返回一个对象。如果您查看该类的方法,它会执行两件事:TextWriter.Syncronized()SyncTextWriterWriteLineAsync()
WriteLineAsync() method calls the synchronous WriteLine() method on the underlying TextWriter that was used to create that SyncTextWriter object.That second point means that the method will not return until the operation has completed. It always returns a completed task. It has no way to return an incomplete task, and if the operation is blocked for any reason, such as that the consumer of the output stream is not consuming it and thus is causing the output buffer to get filled, the call will not return.
This will cause the thread in which you make such a call to block until the write operation can complete, i.e. whatever condition was causing it to block in the first place has been resolved.
Now, all that said:
SetOut() or because the process stdout has been redirected, this may slow the program down depending on how much output your program generates relative to the other work it does, but I doubt you'd experience anything characterized as a "stall". I.e. disk I/O is slow, but it doesn't generally block for extended periods of time.SetOut() and pass some other type of writer, presumably you have control over it and can simply make sure it's written correctly and won't block when being written to.Process.StandardOutput stream, then it behooves that other program to ensure that it keeps up, if it cares about your program being able to continue unimpeded. But that's always the case anyway; the consumer of a process's output streams should always make sure to read them as quickly as possible.I don't personally think it's the concern of a program to itself protect itself against redirected streams that might block, other than of course to not redirect the console streams internally to a destination object that might. Usually, this is considered the job of the receiving process, since it's the one that presumably cares whether the redirected program can do its work.
如果这确实是一个问题,您可以在进程中自己缓冲输出,例如让一个BlockingCollection<string>对象在想要写入输出的线程和执行实际写入的消费者线程之间进行调解。但这并不是那么有用。它只是把罐头踢到路上,因为如果不能指望消耗线程能够不受阻碍地继续,您不想无限期地继续写入集合。如果消费者真的被阻止,集合就会变得太大并OutOfMemoryException在某个时刻抛出异常。对于任何其他试图将写入委托给不同线程的机制,您都会遇到类似的问题,其目标是让当前线程运行而不会阻塞。
恕我直言,最好只是正常编写(即,甚至不用费心使用这些...Async方法,除非发生这种情况,因为您有将编写抽象为 的代码,TextWriter并且打算在支持时异步工作),并依靠 的消费端流式传输“做正确的事”,而不是阻止您的流程。