等待Console.ReadLine()

问题描述 投票:0回答:2

我目前正在构建一个异步控制台应用程序,其中我创建了类来处理应用程序的不同区域。

我创建了一个 InputHandler 类,我设想它会等待 Console.ReadLine() 输入。但是,您不能等待这样的函数(因为它不是异步的),我当前的解决方案就是简单地:

private async Task<string> GetInputAsync() {
    return Task.Run(() => Console.ReadLine())
}

运行完美。然而,我(有限)的理解是调用 Task.Run 将触发一个新的(并行?)线程。这违背了异步方法的目的,因为新线程现在被阻塞,直到 Readline() 返回,对吗?

我知道线程是一种昂贵的资源,所以我觉得这样做真的很浪费而且很笨拙。我也尝试过 Console.In.ReadLineAsync() 但它显然有问题? (好像挂了)。

c# asynchronous console async-await
2个回答
19
投票

我知道线程是一种昂贵的资源,所以我觉得这样做真的很浪费而且很笨拙。我也尝试过 Console.In.ReadLineAsync() 但它显然有问题? (好像挂了)。

不幸的是,控制台流确实有令人惊讶的行为。根本原因是它们“阻止”以确保控制台流的线程安全。就我个人而言,我认为阻塞异步方法是一个糟糕的设计选择,但微软决定这样做(仅适用于控制台流)并且

坚持他们的决定 因此,如果您确实想真正异步读取,则此 API 设计强制

您使用后台线程(例如,

Task.Run)。这不是您通常应该使用的模式,但在这种情况下(控制台流),这是一种可以接受的破解 API 的方法。

  
但是,我(有限)的理解是调用 Task.Run 将触发一个新的(并行?)线程。

不完全是。

Task.Run
会将一些工作排队到线程池中,线程池将让其线程之一执行代码。线程池根据需要管理线程的创建,您通常不必担心它。因此,

Task.Run

并不像每次实际创建一个新线程那么浪费。

虽然我同意

0
投票
方法是可行的,但解决它很容易 - 也许这对某人会有帮助:)

Console.ReadLine()

Console.In

都使用同步流,正如Stephen提到的(第一个实际上只是包装了第二个)。但是,底层原始 
Stream
(可通过 
OpenStandardInput()
 访问)是 
not
 同步的,它被包装在 
StreamReader 级别的同步助手中。因此,一种不产生额外线程的可能解决方案是创建我们自己的 StreamReader
,而不是使用 
Console
 提供的:
using var inputReader = new StreamReader(Console.OpenStandardInput(), Console.InputEncoding);

while (await sr.ReadLineAsync() is string line)
{
   ...
}


© www.soinside.com 2019 - 2024. All rights reserved.