猿问

如何向Console.ReadLine()添加超时?

如何向Console.ReadLine()添加超时?

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

最直截了当的方法是什么?


炎炎设计
浏览 1294回答 3
3回答

MM们

我惊讶地获悉,五年后,所有答案仍然存在以下一个或多个问题:使用的是ReadLine以外的函数,导致功能丢失。(删除/退格/向上键用于先前的输入)。函数在多次调用(产生多个线程、许多挂起的ReadLine或其他意外行为)时表现不好。函数依赖于繁忙的等待。这是一种可怕的浪费,因为等待被期望在任何地方运行,从几秒钟到超时,这可能是多分钟。一个繁忙的等待,跑了这么长的时间,是一个可怕的吸资源,这是特别糟糕的多线程场景。如果用睡眠来修改繁忙-等待,这会对响应性产生负面影响,尽管我承认这可能不是什么大问题。我相信我的解决办法可以解决原来的问题,而不会出现上述任何问题: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所建议的那样:  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并省略超时,使其默认为无限超时。那么我提到的其他解决方案的问题呢?如您所见,使用ReadLine,避免了第一个问题。该函数在多次调用时运行正常。不管是否发生超时,只有一个后台线程将运行,并且最多只有一个对ReadLine的调用将是活动的。调用函数总是会导致最新的输入,或者超时,用户不必多次按Enter键才能提交输入。而且,很明显,这个函数不依赖于繁忙的等待。相反,它使用适当的多线程技术来防止资源浪费。我认为这个解决方案唯一的问题是它不是线程安全的。但是,多个线程实际上不能同时请求用户输入,因此在调用Reader.ReadLine不管怎么说。

达令说

string ReadLine(int timeoutms){     ReadLineDelegate d = Console.ReadLine;     IAsyncResult result = d.BeginInvoke(null, null);     result.AsyncWaitHandle.WaitOne(timeoutms);//timeout e.g. 15000 for 15 secs     if (result.IsCompleted)     {         string resultstr = d.EndInvoke(result);         Console.WriteLine("Read: " + resultstr);         return resultstr;     }     else     {         Console.WriteLine("Timed out!");         throw new TimedoutException("Timed Out!");     }}delegate string ReadLineDelegate();

开心每一天1111

这种方法会使用Consol.KeyAvailable帮助?class Sample {     public static void Main()      {     ConsoleKeyInfo cki = new ConsoleKeyInfo();     do {         Console.WriteLine("\nPress a key to display; press the 'x' key to quit.");// Your code could perform some useful task in the following loop. However, // for the sake of this example we'll merely pause for a quarter second.         while (Console.KeyAvailable == false)             Thread.Sleep(250); // Loop until input is entered.         cki = Console.ReadKey(true);         Console.WriteLine("You pressed the '{0}' key.", cki.Key);         } while(cki.Key != ConsoleKey.X);     }}
随时随地看视频慕课网APP
我要回答