如何向 Console.ReadLine() 添加超时? [英] How to add a Timeout to Console.ReadLine()?

查看:26
本文介绍了如何向 Console.ReadLine() 添加超时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个控制台应用程序,我想在其中给用户 x 秒来响应提示.如果一段时间后没有输入,程序逻辑应该继续.我们假设超时意味着空响应.

I have a console app in which I want to give the user x seconds to respond to the prompt. If no input is made after a certain period of time, program logic should continue. We assume a timeout means empty response.

解决这个问题最直接的方法是什么?

What is the most straightforward way of approaching this?

推荐答案

我很惊讶地发现 5 年后,所有的答案仍然存在以下一个或多个问题:

I'm surprised to learn that after 5 years, all of the answers still suffer from one or more of the following problems:

  • 使用了 ReadLine 以外的函数,导致功能丢失.(删除/退格/向上键用于之前的输入).
  • 函数在多次调用时表现不佳(产生多个线程、许多挂起的 ReadLine 或其他意外行为).
  • 函数依赖于忙等待.这是一种可怕的浪费,因为预计等待会在任何地方运行,从几秒钟到超时,可能是几分钟.运行这么长时间的忙等待是一种可怕的资源消耗,这在多线程场景中尤其糟糕.如果用睡眠修改忙等待,这会对响应产生负面影响,尽管我承认这可能不是一个大问题.

我相信我的解决方案将解决原始问题而不会遇到上述任何问题:

I believe my solution will solve the original problem without suffering from any of the above problems:

class Reader {
  private static Thread inputThread;
  private static AutoResetEvent getInput, gotInput;
  private static string input;

  static Reader() {
    getInput = new AutoResetEvent(false);
    gotInput = new AutoResetEvent(false);
    inputThread = new Thread(reader);
    inputThread.IsBackground = true;
    inputThread.Start();
  }

  private static void reader() {
    while (true) {
      getInput.WaitOne();
      input = Console.ReadLine();
      gotInput.Set();
    }
  }

  // omit the parameter to read a line without a timeout
  public static string ReadLine(int timeOutMillisecs = Timeout.Infinite) {
    getInput.Set();
    bool success = gotInput.WaitOne(timeOutMillisecs);
    if (success)
      return input;
    else
      throw new TimeoutException("User did not provide input within the timelimit.");
  }
}

当然,调用非常简单:

try {
  Console.WriteLine("Please enter your name within the next 5 seconds.");
  string name = Reader.ReadLine(5000);
  Console.WriteLine("Hello, {0}!", name);
} catch (TimeoutException) {
  Console.WriteLine("Sorry, you waited too long.");
}

或者,您可以使用 TryXX(out) 约定,正如 shmueli 建议的那样:

Alternatively, you can use the TryXX(out) convention, as shmueli suggested:

  public static bool TryReadLine(out string line, int timeOutMillisecs = Timeout.Infinite) {
    getInput.Set();
    bool success = gotInput.WaitOne(timeOutMillisecs);
    if (success)
      line = input;
    else
      line = null;
    return success;
  }

具体名称如下:

Console.WriteLine("Please enter your name within the next 5 seconds.");
string name;
bool success = Reader.TryReadLine(out name, 5000);
if (!success)
  Console.WriteLine("Sorry, you waited too long.");
else
  Console.WriteLine("Hello, {0}!", name);

在这两种情况下,您都不能将 Reader 的调用与普通的 Console.ReadLine 调用混合使用:如果 Reader 超时,将会有挂起的 ReadLine 调用.相反,如果您想要正常(非定时)ReadLine 调用,只需使用 Reader 并省略超时,以便它默认为无限超时.

In both cases, you cannot mix calls to Reader with normal Console.ReadLine calls: if the Reader times out, there will be a hanging ReadLine call. Instead, if you want to have a normal (non-timed) ReadLine call, just use the Reader and omit the timeout, so that it defaults to an infinite timeout.

那么我提到的其他解决方案的那些问题呢?

So how about those problems of the other solutions I mentioned?

  • 如您所见,使用了 ReadLine,避免了第一个问题.
  • 该函数在多次调用时行为正常.无论是否发生超时,只有一个后台线程会一直运行,并且最多只有一次对 ReadLine 的调用会处于活动状态.调用该函数将始终导致最新输入或超时,并且用户不必多次按 Enter 键即可提交输入.
  • 而且,显然,该函数不依赖于忙等待.相反,它使用适当的多线程技术来防止资源浪费.

我预见到此解决方案的唯一问题是它不是线程安全的.但是,多个线程不能真正同时要求用户输入,因此无论如何都应该在调用 Reader.ReadLine 之前进行同步.

The only problem that I foresee with this solution is that it is not thread-safe. However, multiple threads can't really ask the user for input at the same time, so synchronization should be happening before making a call to Reader.ReadLine anyway.

这篇关于如何向 Console.ReadLine() 添加超时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆