我想制作一个C#控制台应用程序,它可以在执行某些工作时评估用户输入。为此,我想等待输入异步,类似于:等待控制台。ReadLine()。出于测试目的,我只想在按下Enter键时停止主工作循环的运行。我做到了这一点:
using System;
using System.Threading;
using System.Threading.Tasks;
class WorkTillEnter
{
private static bool running = false;
public static void Main(string[] args)
{
WorkTillEnter.running = true;
WorkTillEnter.observeInputAsync();
DateTime lastTick = DateTime.Now;
while(WorkTillEnter.running){
if(lastTick.Second != DateTime.Now.Second){
Console.WriteLine($"Tick {DateTime.Now}");
lastTick = DateTime.Now;
}
//Doing Work in this loop until enter is hit
}
Console.WriteLine("Worker Terminated.");
}
private static async void observeInputAsync(){
await Task.Delay(1); // <--WHY???
await Console.In.ReadLineAsync();
WorkTillEnter.running = false;
}
}
这很好用,并且每秒钟打印一次"滴答",直到按下Enter为止我现在的问题是:为什么当我删除这一行时它不起作用?await Task.Delay(1); // <--WHY???
在这一行中,程序什么也不做,直到我点击return,然后显然永远不会进入while循环。如何解释这种行为?
这个建议为什么控制台。在.ReadLineAsync块中?解释了当我的可疑行被删除时,Console.In.ReadLineAsync
为什么没有按预期运行。但它并没有解释为什么当添加Line时,它实际上会像预期的那样。
此处await Task.Delay(1);
确保您的程序进入while循环。如果不使用此选项,函数将等待输入。当给出输入时,running
的布尔值变为false
,程序永远不会进入循环。
我不知道await Console.In.ReadLineAsync();
到底为什么要阻止输入。也许是个虫子。♂️
像这样简单的调试过程可以帮助您了解情况。
using System;
using System.Threading.Tasks;
class WorkTillEnter
{
private static bool running;
public static void Main(string[] args)
{
Console.WriteLine("a");
running = true;
Console.WriteLine("b");
ObserveInputAsync();
Console.WriteLine("c");
DateTime lastTick = DateTime.Now;
Console.WriteLine("d");
while (running)
{
Console.WriteLine("e");
if (lastTick.Second != DateTime.Now.Second)
{
Console.WriteLine($"Tick {DateTime.Now}");
lastTick = DateTime.Now;
}
//Doing Work in this loop until enter is hit
}
Console.WriteLine("f");
Console.WriteLine("Worker Terminated.");
}
private static async void ObserveInputAsync()
{
Console.WriteLine("1");
await Task.Delay(1); // <--WHY???
Console.WriteLine("2");
await Console.In.ReadLineAsync();
running = false;
Console.WriteLine("3");
}
}
感谢Andreas Huber给出原因。Console.In.ReadLineAsync()
被窃听并实际阻塞,直到提交输入。但是有问题的Line将异步函数推送到一个新的Thread。测试代码如下:
using System;
using System.Threading;
using System.Threading.Tasks;
class WorkTillEnter
{
private static bool running = false;
public static void Main(string[] args)
{
WorkTillEnter.running = true;
Console.WriteLine($"before Asnyc called: {Thread.CurrentThread.ManagedThreadId}");
WorkTillEnter.observeInputAsync();
Console.WriteLine($"after Asnyc called: {Thread.CurrentThread.ManagedThreadId}");
DateTime lastTick= DateTime.Now;
while(WorkTillEnter.running){
if(lastTick.Second != DateTime.Now.Second){
Console.WriteLine($"Tick {DateTime.Now}");
lastTick = DateTime.Now;
}
//Doing Work in this loop until enter is hit
}
Console.WriteLine("Worker Terminated.");
}
private static async void observeInputAsync(){
Console.WriteLine($"Async before await: {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(1); // <--WHY???
Console.WriteLine($"Async after first await: {Thread.CurrentThread.ManagedThreadId}");
await Console.In.ReadLineAsync();
Console.WriteLine($"Async after second await: {Thread.CurrentThread.ManagedThreadId}");
WorkTillEnter.running = false;
}
}
输出结果:(你可以看到我在哪一点点击返回)
before Asnyc called: 1
Async before await: 1
after Asnyc called: 1
Async after first await: 4
Tick 11.05.2021 20:30:42
Tick 11.05.2021 20:30:43
Async after second await: 4
Worker Terminated.
但删除行后,输出如下:
before Asnyc called: 1
Async before await: 1
Async after first await: 1
Async after second await: 1
after Asnyc called: 1
Worker Terminated.